I'm not keen on the standard behavior of the Play Games Service to automatically attempt a connection when the app is first launched, so I have disabled this. In my main menu I have a 'display scores' button. What I want to happen when the user presses this button is this:
If the user is connected (logged in), go ahead and display the leaderboard
If the user is not connected, then display the connection dialog. Once connected, display the leaderboard
On the main menu, I will have an extra button "Log out" which will display only if the user is connected / logged in.
When the user clicks the button, I am carrying out the following:
Code
if (buttonPressed()){
//Display connection dialogue and initiate log in
getGameHelper().beginUserInitiatedSignIn();
//Check if the user is signed in before continuing
if (getGameHelper.isSignedIn()){
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), myLeaderBoardID), 1);
}
}
If the user isn't connected: The user is presented with a connection dialogue - this works fine. They can then log in. Once they have done this, nothing else happens (the code has moved on and therefore does not display the leaderboard because the user isn't logged in - if I don't have the check to see if the user is signed in here the app would just crash). If the user then presses the button again, it will display the leaderboard.
How can I do all this with just one button press?
What I want is, if the user isn't logged in, to display the log-in dialogue, then as soon as the user has logged in, display the leaderboard. I need to make startActivityForResult wait until the user has completed sign in.
In short
I need to make my code wait until it's connected to Play before attempting to display the Leaderboard.
Any help would be appreciated
You can be notified of successful/failed sign-in as follows:
getGameHelper().setup(
new GameHelper.GameHelperListener() {
#Override
public void onSignInSucceeded() {
// execute code on successful sign-in
// for example, here you could show your leaderboard
}
#Override
public void onSignInFailed() {
// execute code on failed sign-in
}
};
);
You should of course do this before you attempt to sign-in. You can then show your leaderboard when sign-in succeeds. This code should be placed where you create your game helper (i.e. before the buttonPressed() code is executed).
Once this code is in place, you should change your buttonPressed() code to look as follows:
if ( buttonPressed() ) {
// check if user already signed-in and show leaderboard; otherwise do sign-in
if ( getGameHelper.isSignedIn() ) {
startActivityForResult( Games.Leaderboards.getLeaderboardIntent( getApiClient(), myLeaderBoardID ), 1 );
}
else {
getGameHelper().beginUserInitiatedSignIn();
// NOTE: do nothing further here; show the leaderboard in
// the listener's onSignInSucceeded()
}
}
One final note: the listener you create will be called for all sign-in operations, so if you need to have this functionality in multiple places (for example, if you want to do the same with achievements) then you will need to use some signal as to what needs to happen on successful sign-in and take the correct action in onSignInSucceeded().
Signalling an action for sign-in success:
Add this code to you class (global scope)
public final static int NO_ACTION = 0;
public final static int SHOW_LEADERBOARD = 1;
public final static int SHOW_ACHIEVEMENTS = 2;
public int signInAction = NO_ACTION;
Next set the action just before signing-in (based on where the sign-in occurs):
if ( buttonPressed() ) {
// check if user already signed-in and show leaderboard; otherwise do sign-in
if ( getGameHelper.isSignedIn() ) {
startActivityForResult( Games.Leaderboards.getLeaderboardIntent( getApiClient(), myLeaderBoardID ), 1 );
}
else {
// NEW: request leaderboard to be shown upon sign in
signInAction = SHOW_LEADERBOARD;
// NEW----------------------------------------------
getGameHelper().beginUserInitiatedSignIn();
// NOTE: do nothing further here; show the leaderboard in
// the listener's onSignInSucceeded()
}
}
And finally change the listener to respond the set sign-in action:
getGameHelper().setup(
new GameHelper.GameHelperListener() {
#Override
public void onSignInSucceeded() {
if ( signInAction == SHOW_LEADERBOARD ) {
// show your leaderboard here
}
else if ( signInAction == SHOW_ACHIEVEMENTS ) {
// show achievements here
}
// important! reset the sign-in action so that any subsequent sign-in
// attempts do not re-use the currently set action!
signInAction = NO_ACTION;
}
#Override
public void onSignInFailed() {
// execute code on failed sign-in
// important! it should also be cleared in case of an error
signInAction = NO_ACTION;
}
};
);
Of course, this is just one way to achieve this, but it should work just fine for most purposes. Just be sure to set the signInAction to the appropriate value before you perform the sign-in - and be sure to clear it when sign-in is complete.
Related
Using AppCenter I am able to send push notification to all my devices with my Xamarin Forms (android only) app.
Since my devices, are going to be shared, I can't do the filter of the notifications on the AppCenter side based on the devices IDs.
I need to make the filter based on the current logged in user to my application. For this with the push notification I also send the WorkerID, which serves as a filter.
While I'm able to do this filter when the app is in foreground, its not working when the app is in background or not running.(normal behaviour since the push event is in App Start)
protected override void OnStart()
{
// This should come before AppCenter.Start() is called
// Avoid duplicate event registration:
if (!AppCenter.Configured)
{
Push.PushNotificationReceived += (sender, e) =>
{
var title = e.Title;
var message = e.Message;
// If app is in background title and message are null
// App in foreground
if (!string.IsNullOrEmpty(title))
{
foreach (string key in e.CustomData.Keys)
{
if (e.CustomData[key] == Settings.WorkerID)
{
Current.MainPage.DisplayAlert(title, message, "OK");
}
}
}
};
}
// Handle when your app starts
AppCenter.Start("android=xxxxxxxxxxxxxxxxxx", typeof(Push));
}
Is there a way to intercept and filter the push notifications when the app is in background and block them when the app is not running (since no user is yet logged in) ?
To filter users when sending push notifications it's preferable to set user id:
AppCenter.SetUserId("your-user-id");
Then on the appcenter.ms go to Push > Send notificaiton. Fill in the required fields.
And then in the second step select User list instead of All registered devices. Then enter user ids, separated by commas.
Through the document, you can enable-or-disable-push-at-runtime, so can enable or disable push when use go to background or go back to foreground, like this:
protected override void OnSleep()
{
// Handle when your app sleeps
Push.SetEnabledAsync(false);
}
protected override void OnResume()
{
// Handle when your app resumes
Push.SetEnabledAsync(true);
}
You can also enable or disable push when user login or login out:
public void userLogin() {
Push.SetEnabledAsync(true);
}
public void userLoginOut() {
Push.SetEnabledAsync(false);
}
Set it in the right place to meet your requirement.
I want to show leaderboard score directly as player press on leaderboard icon as like this:
When I was showing a leaderboard it just displaying, list of leaderboard. I want to see actual score directly.
Here is my code:
public void ShowLeaderboard ()
{
if (Social.localUser.authenticated)
Social.ShowLeaderboardUI ();
else {
// authenticate user:
Social.localUser.Authenticate ((bool success) => {
// handle success or failure
if (success) {
Debug.Log ("Login Success....");
PostHighScoreOnLeaderBoard();
Social.ShowLeaderboardUI ();
} else {
Debug.Log ("Login Failed....");
}
});
}
}
How can I show directly a players score?
If you wish to show a particular leaderboard instead of all leaderboards, you can pass a leaderboard ID to the method. This, however, is a Play Games extension, so the Social.Active object needs to be cast to a PlayGamesPlatform object first:
using GooglePlayGames;
using UnityEngine.SocialPlatforms;
...
// show leaderboard UI
PlayGamesPlatform.Instance.ShowLeaderboardUI("Cfji293fjsie_QA");
If you would like the show the user's score directly like in your first image, you need to call PlayGamesPlatform.Instance.ShowLeaderboardUI("leaderboard_id") with the leaderboard ID passed in instead of Social.ShowLeaderboardUI().
I have a couple questions of how to implement google game services in my app.
First of all, after I checked that the user is signed in and the client is connected, I launch
Intent intent = Games.TurnBasedMultiplayer.getSelectOpponentsIntent(mGoogleApiClient, 1, 1, true);
startActivityForResult(intent, RC_SELECT_PLAYERS);
To show the user a dialog where they can select the opponent.
After I get the result from the activity I execute this code
if (request == RC_SELECT_PLAYERS) {
Log.e(LOG_TAG, "Got RC_SELECT_PLAYERS result intent");
if (response != Activity.RESULT_OK) {
// user canceled
return;
}
// Get the invitee list.
final ArrayList<String> invitees = data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// Get auto-match criteria.
Bundle autoMatchCriteria;
int minAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers = data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
TurnBasedMatchConfig turnBasedMatchConfig = TurnBasedMatchConfig.builder()
.addInvitedPlayers(invitees)
.setAutoMatchCriteria(autoMatchCriteria)
.build();
// Create and start the match.
Games.TurnBasedMultiplayer
.createMatch(mGoogleApiClient, turnBasedMatchConfig)
.setResultCallback(new MatchInitiatedCallback());
}
To initiate the match. The problem is, the opponent I challenged doesn't get any notification where he is asked to join the game. So when the user gets a notification to join a game, how can I catch this notification and show the user the appropriate content? Which intent result should I look for?
In my MatchInitiatedCallback I check which turn it is now:
public class MatchInitiatedCallback implements ResultCallback<TurnBasedMultiplayer.InitiateMatchResult> {
private static final String LOG_TAG = "MatchInitiatedCallback";
#Override
public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
// Check if the status code is not success.
Status status = result.getStatus();
if (!status.isSuccess()) {
Log.e(LOG_TAG, "showError() " + status.toString());
//showError(status.getStatusCode());
return;
}
TurnBasedMatch match = result.getMatch();
// If this player is not the first player in this match, continue.
if (match.getData() != null) {
Log.e(LOG_TAG, "Not my turn");
//showTurnUI(match);
return;
}
// Otherwise, this is the first player. Initialize the game state.
//initGame(match);
Log.e(LOG_TAG, "initGame()");
// Let the player take the first turn
//showTurnUI(match);
Log.e(LOG_TAG, "showTurnGui()");
}
}
But this code gets executed even before my opponent selects to join.
Shouldn't he first be able to accept or decline the game?
Can someone please tell me if I'm doing this properly or if this is supposed to be like this? If not, how should it be implemented correctly?
EDIT: I took all this code from the documentation. It does show some code samples of how to implement things, but not of how the code all comes together and the order in which things should be executed, or how to handle notifications and such.
Yes, it is supposed to work like this. You must take a turn before the opponent actually receives the invitation. In fact, if you invite several opponents, each of them will have to accept the invitation and take a turn before the next opponent is invited, meaning it can take quite a while before you know whether you actually got a match going.
To avoid asking the users to take turns during the invitation phase, your program can take a dummy turn for each user to pass the invitation to the next user. When all users have joined you can start to take real turns.
I'm writing my app that contains login facebook function.
As this moment, my app can jump to another fragment(post-login page) after logging-in
And I use finish(); after startActivity(intent); to avoid users going back to login page if they logged-in successfully.
However, I am facing a new problem.
If I try to press back key in post-login page, it will go back to the main menu of Android. Sounds good. But when I try to open my app again, it starts my login page again with a logout button. After 2 secs, it jumps to my post login page.
Is there any way to prevent this?
I hope my app can open the post-login page directly after I try to restart my app if the user logged-in successfully before.
Cheers~
Set a boolean isLoggedIn in Shared Preferences after you login default initial value being false.
If login was succesfull update isLoggedIn to true.
Now when app restarts check the value of isLoggedIn.
If isLoggedIn value is true, start post login Activity else start login Activity.
Of course you can do this, you could just create a File into this path (after User logged in):
context.getExternalFilesDir(null).getAbsolutePath()
After you created - just check at Start of the Application if the file is on Users device, and link it to your MainMenu.
If you did successfully save the File in this Path (you prevent after a User deinstalls and reinstalls the app from not loggin in anymore. (This workflow is also used in Whatsapp, if you delete Data, you got to log in again -for example if somebody sells his smartphone to an other user, who reinstalls exactly this app, the file will be automatically deleted, so he got to log in or even sign up again)
public class InstallCertificate {
private Context context = null;
private File certificate = null;
public InstallCertificate(Context context) {
this.context = context;
}
public void createCertificateAtVerifying() {
try {
certificate = new File(context.getExternalFilesDir(null)
.getAbsolutePath(), "InstallationCertificate");
certificate.createNewFile();
System.out
.println("successfully installed Certificate on cell phone");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public boolean checkIfCertificateIsInstalled() {
boolean certificateExists = false;
certificate = new File(context.getExternalFilesDir(null)
.getAbsolutePath(), "InstallationCertificate");
if (certificate.exists()) {
return true;
}
return certificateExists;
}
Signing out or disconnecting the GamesClient is straightforward when it is from your own UI, such as a button on the main menu.
However, users can also sign out from the game from the Google Play UI in the acheivements and leaderboard views displayed by the intents such as getAllLeaderboardsIntent(). (It's a bit hidden, but if you tap the menu in the upper right, it lets you sign out.)
There are a few promising listener interfaces like OnSignOutCompleteListener but they don't seem to work with a sign out via the google UI, only from your own UI calling GamesClient.signOut().
How can I detect that the user has signed out from the leaderboards or achievement intents? Is it possible to have a callback for this?
I want to be able to update my in-game UI to reflect the logged-in status.
Unfortunately GameHelper doesn't detect when you logout from Google play games.
What you need to do is to put this in your onActivityResult() method in your activity.
I encounter a crash error when I tried using aHelper.signOut() when res == RESULT_RECONNECT_REQUIRED is true.
Instead I created a resetAllValues() method which resets back all values to its default in GameHelper.
In my MainActivity.java
protected void onActivityResult(int req, int res, Intent data) {
super.onActivityResult(req, res, data);
if (res == GamesActivityResultCodes.RESULT_RECONNECT_REQUIRED) {
aHelper.resetAllValues();
} else {
aHelper.onActivityResult(req, res, data);
}
}
My method in GameHelper.java
public void resetAllValues()
{
mProgressDialog = null;
mAutoSignIn = true;
mUserInitiatedSignIn = false;
mConnectionResult = null;
mSignInError = false;
mExpectingActivityResult = false;
mSignedIn = false;
mDebugLog = false;
}
Duplicate from:
How can i check if user sign's out from games services default view?
As I see it, there is no elegant solution to that. You can check the response_code in onActivityResult for INCONSISTENT_STATE and cut off the GamesClient, but I'm not sure, if you can potetially get to an inconsistent state in any other manner...