Tracking Wins and Loses in Google Play Game Services - android

I am implementing a Turn Base Multiplayer game using Google Play Services. There seems to be a major feature missing from it though: tracking wins and loses! Seems like a pretty important feature for any sort of competitive game.
Am I missing something? Is this already handled by Google in some way?
If not, I am wondering if anyone has implemented their own w/l tracking system, and how they approached it. I am worried about just saving it locally, as it might get out of sync with reality. I suppose I could use Google Cloud Storage, but I also worry that keeping track of which matches have been accounted for could be a little error prone (eg. counting wins/loses on the same match multiple times). Maybe using the Google Play Leaderboard system would be good, as you could compare with friends/etc.

You might want to try using the Events provided by Google Play Game Services. Here's the steps for using it:
Go to the Android Developer Console
On the sidebar click on Game Services, choose your App, then Events
Then create two new Events, one called 'Games Won' and the other 'Games Lost', then click to publish your changes
Click the Get Resources link to see the resource ids of your new events, and add them to your App in the res/values directory
When a game is won or lost, call the following code, where eventRef is your friendly resource name you added in the last step, either "events_games_won" or "events_games_lost":
int eventInt = activity.getApplicationContext().getResources().getIdentifier(eventRef, "string", "com.yourpackage.android");
String eventID = activity.getString(eventInt);
Games.Events.increment(apiClient, eventID, 1);
If you're using basegameutils, your apiClient instance can be obtained with aHelper.getApiClient(), otherwise follow these instructions to set it up.
To read the data you've saved, you can use a callback like this:
PendingResult<Events.LoadEventsResult> results = Games.Events.load(apiClient, true);
results.setResultCallback(new ResultCallback<Events.LoadEventsResult>() {
#Override
public void onResult(Events.LoadEventsResult result)
{
Events.LoadEventsResult r = (Events.LoadEventsResult)result;
EventBuffer eb = r.getEvents();
for (int i=0; i < eb.getCount(); i++) {
Event event = eb.get(i);
// do something, like cache the results for later
YourGameState.eventStats.put(event.getName(), (int)event.getValue());
}
eb.close();
listener.onResult();
}
});
The benefits of this approach over maintaining and managing counts locally are:
the wins and losses are stored in Google Play's cloud, and they'll be stored across all the user's devices
you can use the Events to create Quests (also described on Google Play), such as "Win 10 games this week", or "Go this week undefeated"
Google Play will give you stats on Events for everyone who plays your game, which can be very useful for analysing player activity and performance
And, of course, you can use the same approach to create Events for anything you want.

It depends on your implementation. I've created a chess application and I just use SharedPreferences to keep track of my wins and losses. If you use it properly it won't be error prone.
Eg.
SharedPreferences prefs = this.getSharedPreferences(
"com.example.app", Context.MODE_PRIVATE);
if (gameOver(Side.White)) {
prefs.edit().putLong(dateTimeKey, prefs.getLong(losses, 0) + 1).commit();
} else if (gameOver(Side.Black)){
prefs.edit().putLong(dateTimeKey, prefs.getLong(wins, 0) + 1).commit();
}

Related

Is there a way to update from Adobe Air (flash) android app to a Unity3d app and keep the local save that is in shared object?

This is the situation: We have an android game that has been published for a few years now, that was originally developed in ActionScript3 and built with Adobe Air...
Now, the problem we are facing is that because ActionScript3 is basically unsupported by most advertising and analytics SDKs, we need to update to something newer, without losing our current playerbase. So we started developing a clone of the current game in Unity3d, and also found a way to sign with the old .P12 and the playstore console lets us upload and everything.
Now to the real question: The last and current hurdle we have to overcome is find a way to preserve the current users' save games when they update to the Unity version. We use a SharedObject to store all user preferences and progress.
I have searched forums, here in SO and in the Unity3D forums and found no one asking a similar question.
But we would like to know if someone knows a way for another app, with the same signature and packagename (is basically an update to the AdobeAir app) to read the SharedObject from the AdobeAir App and parse it so it can create a local save with Unity3D (with PlayerPrefs or any other method).
The code we use to Save and Load progress from a SharedObject is this:
public function LoadVal(_id:String, _defaultValue:Object = null):Object
{
if (existSO(_id))
{
return loadSO(_id);
}
else {
return _defaultValue;
}
}
private function loadSO(id:String):Object
{
mySO = SharedObject.getLocal(nameSO);
return mySO.data[id];
}
public function existSO(id:String):Boolean
{
mySO = SharedObject.getLocal(nameSO);
return mySO.data[id] != null;
}
public function SaveVal(id:String,val:Object):void
{
mySO = SharedObject.getLocal(nameSO);
mySO.data[id] = val;
mySO.flush()
}
public function clearSO():void
{
mySO = SharedObject.getLocal(nameSO);
mySO.clear();
}

Play single track spotify sdk

I am using the Spotify android SDK, and I am trying to get a single song to play, and I would like to potentially play a song after the current one is completed. The issue is that after the song completes Spotify plays a random song afterwards. Is it possible to play the song and not have anything else automatically play after it?
I am simply calling the app remotes player API play function,
mSpotifyAppRemote?.getPlayerApi()?.play(uri)
#Mikee you are doing nothing wrong, Spotify messes around with track replay if you are only using the Free version, if you use Premium it will work correctly. Funny enough if you try playing by an alblum or artist that works with the Free version.
I'm not an expert but from their documentation it looks like you could watch the PlayerState. I'm also not sure when a PlayerState event would trigger but if it's coming back relatively often you could check the track value and see if it's gone to null, or another value and work using that.
Here's a Java example from their website:
// Subscribe to PlayerState
mSpotifyAppRemote.getPlayerApi()
.subscribeToPlayerState()
.setEventCallback(new Subscription.EventCallback<PlayerState>() {
public void onEvent(PlayerState playerState) {
// See what values are in playerState, might be able to determine
// if it's now randomly playing?
final Track track = playerState.track;
if (track != null) {
Log.d("MainActivity", track.name + " by " + track.artist.name);
// If the track is now different, your song has finished, stop it?
}
}
});
I've put a few extra comments in the code above that might yield some results!

Baidu maps on Android: access key does not work for location searching

I'm creating an Android app for a chinese client and they need map integration, so Google maps is not an option since all Google services are blocked in China. I'm trying to use Baidu maps, which is called Baidu LBS (location-based services) cloud.
Getting a basic map with no overlays to work was relatively easy. The process is described here (in Chinese, but the code speaks for itself if you don't understand the language). Downloading the latest Baidu Android SDK (v3.2.0 at time of writing) and integrating it into my Eclipse project as a library was no problem, but don't trust the documentation in that link too much even though it is the official one. Their examples often contain code that wouldn't even compile. The name of the .jar file for example was completely different from what you see in their screenshot.
Oh and also their .jar library is obfuscated which is super annoying to work with :-(
I needed to register a Baidu account and go to their control center to generate a key. To create an access key ("ak") for mobile you need to enter the SHA1 fingerprint of the keystore which signs your app, followed by the package name specified in your manifest.
Then I added the generated key to my manifest under the tag
<meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="xxx...xxx" />
I then copied code from their sample project's CloudSearchActivity because I have specific coordinates that I would like to display. I implemented the CloudListener interface as shown:
#Override
public void onGetSearchResult(final CloudSearchResult result, final int error)
{
Log.w("onGetSearchResult", "status=" + result.status + ". size=" + result.size + ". total=" + result.total + ". error=" + error);
if(null != result && null != result.poiList && 0 < result.poiList.size())
{
mBaiduMap.clear();
final BitmapDescriptor bitmapDescriptor=BitmapDescriptorFactory.fromResource(R.drawable.icon_address_grey);
LatLng latitudeLongitude;
LatLngBounds.Builder builder=new Builder();
for(final CloudPoiInfo info : result.poiList)
{
latitudeLongitude=new LatLng(info.latitude, info.longitude);
final OverlayOptions overlayOptions=new MarkerOptions().icon(bitmapDescriptor).position(latitudeLongitude);
mBaiduMap.addOverlay(overlayOptions);
builder.include(latitudeLongitude);
}
final LatLngBounds bounds=builder.build();
MapStatusUpdate mapStatusUpdate=MapStatusUpdateFactory.newLatLngBounds(bounds);
mBaiduMap.animateMapStatus(mapStatusUpdate);
}
}
And I added code to launch a query (also copied from their sample project):
#Override
public View onCreateView(final LayoutInflater layoutInflater, final ViewGroup viewGroup,
final Bundle savedInstanceState)
{
// initialize needs to be called
SDKInitializer.initialize(getApplication());
CloudManager.getInstance().init(MyFragment.this);
view=(ViewGroup)layoutInflater.inflate(R.layout.fragment_map, viewGroup, false);
mMapView=(MapView)view.findViewById(R.id.baiduMapView);
mBaiduMap=mMapView.getMap();
NearbySearchInfo info=new NearbySearchInfo();
info.ak="xxx...xxx";
info.geoTableId=12345;
info.tags="";
info.radius=30000;
info.location="116.403689,39.914957";
CloudManager.getInstance().nearbySearch(info);
return view;
}
Unfortunately I keep getting a status value of 102 from the server (according to this API page that means STATUS_CODE_SECURITY_CODE_ERROR. Now I don't know what to do.
Things that I don't understand:
Why do I need to repeat my access key ("ak") when building the query? Is it not enough to have it in the manifest once?
What is this "geoTableId" value in the query supposed to be?
Any ideas?
After many hours of research I have made some progress on the open questions.
The reason for the "ak" field in a cloud search query is not duplication, it is in fact a different access key. Somewhere in a hidden place Baidu says that access keys "for mobile" will not work for these cloud searches, you need an ak "for server". So the solution is to go back to the Baidu control center and create another key "for server". This key needs to be used in the query, while the "for mobile" key needs to remain in the manifest.
geoTableId is an identifier of your account, not unsimilar to the access keys. It is a (currently) 5 digit number that you need to obtain in the Baidu control center. The other keys were generated in the tab titled "API控制台" (API control desk), but for the geoTableId you need to switch to the tab called "数据管理" (data management). There I think I needed to press the "创建" (~create) button on top left, then enter a name, select "是" (yes) where they ask if this is for release (not sure about that translation) and then click "保存" (save). After this, your freshly generated number is displayed in the top field in parentheses behind the name you chose just now.
These steps have allowed me to send "successful" queries where the server answers with status 0 (STATUS_CODE_SUCCEED). However, so far all the answers I get are empty, I have yet to find a query which produces a non-empty answer. If anyone manages to do that, please let me know!

Google Play Games Service - Get List of running matches

I'm working on a TurnBased Game with the Google Play Games Service.
Now I would like to list all Games you are involved in the DrawerMenu so you could enter the games very easy and also see what games you are in...
My Question is, how do I get these Games and also how do I get them so I can reenter them on a click?
Hope I could make my Problem clear :)
Thank you!
This is how I did it:
static final int[] statusesToLoad = new int[]{
TurnBasedMatch.MATCH_TURN_STATUS_INVITED,
TurnBasedMatch.MATCH_TURN_STATUS_MY_TURN,
TurnBasedMatch.MATCH_TURN_STATUS_THEIR_TURN,
TurnBasedMatch.MATCH_TURN_STATUS_COMPLETE};
PendingResult<TurnBasedMultiplayer.LoadMatchesResult> loadMathesResult = Games.TurnBasedMultiplayer.loadMatchesByStatus(mGoogleApiClient, statusesToLoad);
loadMathesResult.setResultCallback(new loadMatchesCallback());
And then in the callback you can get data buffers for all the active games you are involved in and all the invitations you received:
private class loadMatchesCallback implements ResultCallback<TurnBasedMultiplayer.LoadMatchesResult>{
#Override
public void onResult(TurnBasedMultiplayer.LoadMatchesResult loadMatchesResult) {
LoadMatchesResponse response = loadMatchesResult.getMatches();
TurnBasedMatchBuffer myTurnMatches = response.getMyTurnMatches();
TurnBasedMatchBuffer theirTurnMatches = response.getTheirTurnMatches();
TurnBasedMatchBuffer completedMatches = response.getCompletedMatches();
InvitationBuffer invitations = response.getInvitations();
}
}
}
You can use these buffers just as you use ArrayList, but you need to keep in mind that google wants you to release() them after you are done. If you won't you're gonna get a notification in your logs about a data leak.
You should use this method:
Games.TurnBasedMultiplayer.getInboxIntent(GoogleApiClient apiClient);
According to the documentation of the method, this method returns an Intent that can be used to start an activity that shows invitations and matches.
Hope this helps. Any other questions feel free to comment and I'll try to answer.
in iOS it is like this:
this one gets all matches where you have been invited and are waiting for you to answer, you can then change the GPGTurnBasedUserMatchStatusInvited to another type with autocomplete.
GPGTurnBasedModel *turnModel = [GPGManager sharedInstance].applicationModel.turnBased;
NSArray *invited = [turnModel matchesForUserMatchStatus:GPGTurnBasedUserMatchStatusInvited];
there is also a function to get ALL the matches but it includes the finished ones, maybe you don't want that.

How to notify users about an Android app update?

I've built an Android app which is now on Play Market. From time to time, I make updates to it, and I'd like to let users know that a new version is available.
How can I send an update notification to the users of the app?
You do not need to do anything specific for this. Since you mentioned that you are using Google Play, the update notification is taken care of by Google Play.
You just need to update the APK with a higher versionCode and Google Play should do the rest.
Update 2020: now you can use in-app updates mechanism
Docs: https://developer.android.com/guide/playcore/in-app-updates
You can do this in a lot of ways, depending on when you want the user to be able to see that there is an update available.
If you want the user to know about the update when the app is started, just create a utility method (inside the onCreate method of your main/first Activity) that checks if a newer version is available in Google Play. If it does, display an alert dialog with a relevant message and an Intent which opens your app in Google Play when the user clicks on the positive button of the alert dialog.
If you are updating the app regularly, the user will keep getting this alert dialog every time the app is started and hence, may get irritated. Thus, this is not the best approach.
If you want the user to get a notification on the phone (and not when the user starts the app), you can use the AlarmManager class to schedule a background service which checks for an update at regular intervals. If the service finds that an upgrade is actually available, publish a notification with an intent that opens your app in Google Play.
Of course, another approach is to leave it to the OS itself. If the user has not set the "Automatically update" preference for your app, the user will get a notification regularly about an update available for your, as well as any other apps.
But not all users enable background data on their devices, so this is not completely reliable.
In the end, you must respect the users preferences. If the user does not want to automatically update the app, or does not want to see a nagging dialog box whenever he/she starts your app, don't alert the user about the update.
In my opinion, you should create a PreferenceActivity that has a preference like "Check for updates regularly", which can be set from within your app. If it is set, do the needful in your own service. May be even give the user an option to select the period after which the service will check for an update.
I hope this helps!
It is up to each phone owner if she wants to be notified on new versions by google play, and it's up to each phone's manufacturer if this is to be enabled by default.
If you however are in a situation where you "require" the user to update to the new version to be compatible with some form of protocol or you have a similar similar use case where you have a server component somewhere, you might want to notify the user of a potential version conflict in the UI based on information about what is the latest version.
This information can be grabbed directrly from google play, however as #Yahel pointed out in this question google play is a closed system with no official API, and you might need to rely on unpredictable undocumented API. There is an unofficial API library here.
This leaves only one option, which is to keep this information on your own server. If you allready have a serverside this might be trivial. Simply put the latest version in an XML file and retreive that at regular intervals from your code. If the version code is outdated, trigger the notification in your UI. Here is an example implementation for doing that.
I hope this was helpful :-)
I know this is an old question but still if people are coming here to check this question, Google is now providing official support for in-app notification for application update the full documentation can be found here
Use this : https://www.push-link.com/
Google Play will notify your users that the app has an update via the notification bar.
If you set up a notification system yourself, the likely result would be that, although the user is notified of an update sooner, when he/she goes to Google Play to install the update it will not yet be available. This is because there is a lag from the time you "publish" an app/update and the time until it appears on Play. Telling your users that there is an update when the update is unavailable would only lead to confusion and frustration.
My advice: stick with Google's update notification system and don't worry about trying to get users an update 15 minutes sooner.
Some people use Android Cloud-to-Device Messaging (C2DM) to notify their users of updates. I don't think I'd bother, since I think Google Play does a pretty good job of notifying me of updates already, and implementing C2DM adds a whole new dimension to writing an app (because it requires a server component). But maybe you want to offer your users a richer update notification than you get from Google Play.
#Davek804's answer above is wrong. android:versionCode is an integer value that represents the version of the application code, relative to other versions, so using "1.5b" there is incorrect. Use "15" (or "150") instead
Found a nice solution for your problem:
Let´s say you want to check for version updates manually on app start and notify your users for the new Update.
Step 1: Download android-market-api (not the .jar file, the full project!)
Step 2: After importing it to eclipse, write in your activity the following code:
MarketService ms = new MarketService(activity);
ms.level(MarketService.REVISION).checkVersion();
now, we need to modify MarketService.java, because it seems to be broken.
Step 3: rewrite callback method and add the following methods
protected void callback(String url, JSONObject jo, AjaxStatus status){
if(jo == null) return;
String googlePlayversion = jo.optString("version", "0");
String smartphone_version = "";
PackageInfo pInfo;
try {
pInfo = act.getPackageManager().getPackageInfo(act.getPackageName(), 0);
smartphone_version = pInfo.versionName;
} catch (NameNotFoundException e) {}
boolean new_version_avaible = compare(smartphone_version, googlePlayversion);
if(new_version_avaible){
showUpdateDialog(jo);
}
}
private static boolean compare(String v1, String v2) {
String s1 = normalisedVersion(v1);
String s2 = normalisedVersion(v2);
int cmp = s1.compareTo(s2);
String cmpStr = cmp < 0 ? "<" : cmp > 0 ? ">" : "==";
System.out.printf("result: "+"'%s' %s '%s'%n", v1, cmpStr, v2);
if(cmpStr.contains("<")){
return true;
}
if(cmpStr.contains(">")||cmpStr.contains("==")){
return false;
}
return false;
}
public static String normalisedVersion(String version) {
return normalisedVersion(version, ".", 4);
}
public static String normalisedVersion(String version, String sep, int maxWidth) {
String[] split = Pattern.compile(sep, Pattern.LITERAL).split(version);
StringBuilder sb = new StringBuilder();
for (String s : split) {
sb.append(String.format("%" + maxWidth + 's', s));
}
return sb.toString();
}
If you want to test it, modify googlePlayversion string to a higher version than your local one.
The source comparison method I used is from How do you compare two version Strings in Java?
There is also a very good approach for checking version and give user in app notification or when you want to forcefully update the application if you can decide the first connection of your app with the server.In the response of the first request you can send the current version of app stored on your server and then on client end you can take the appropriate action.
Advantages of this approach-:
1-No extra request for version no.
2-It is also applicable if you are downloading the app other than the google playstore.
3-you can also use this idea if you want to check the version at particular operation of your app ex- transaction(if you add a new payment gateway.)
Don't know if you want to walk extra miles. You can try out google appengine, which serve version number for your app and let you android app check the appengine to see if there is a new version when the application is launched. That way, it does not matter if your app is in google play market nor amazon app store nor if it is installed on the phone without those two via sideloading. It is not very hard to setup appengine just for serving your application version in json. Replace "Hello World" string with your app version name ...
This can be using a simple webservice just this is one of the way to acheive.
i.e., when ever the app launch hit that webservice with the current version of the user app and on the server you need to check whether any new version is available or not(Must maintain the newest version of the app) and send the corresponding response to the user. If any newer version is available prompt the user to download the newest version of the application and if no newest version is available then allow the user to continue.
Hope so atleast something must be useful to you.
There are two models that are basically used to tackle the issue.
Pull Based
Push Based
Its depends on the architecture or design of particular system that determines whether pull based or push mechanism is used.
For pull based model you just make one http request to concerned server regarding the new version of application. The current application version no can be saved in SQLLite in android application. This can be given to server and new version can be checked against it at the server.
For push mechanism you can use C2DM push notification service.. details of which are given at http://code.google.com/android/c2dm/
Generally when you upload a new application to Google play most users get a notification about an update, some will have the app automatically downloaded to their device, depending on the settings they have.
If you seriously want to make a notification from your app to ask them to update (so that everyone gets the notification, whatever their Google play settings are, then you will have to make a web service which returns the number of the newest version. You can then compare that inside your app and post a notification. You could use Google App Engine ( https://developers.google.com/appengine/) because that works with eclipse and java, which you probably already have.
I would not recommend this approach as it creates a lot of work for you to provide something that most users have already got.
i think this is too late but it can be help some one
public enum AppVersionUpgradeNotifier {
INSTANCE;
private static final String TAG = "AppVersionUpdateManager";
private static final String PREFERENCES_APP_VERSION = "pref_app_version_upgrade";
private static final String KEY_LAST_VERSION = "last_version";
private SharedPreferences sharedPreferences;
private VersionUpdateListener versionUpdateListener;
private boolean isInitialized;
public static synchronized void init(Context context, VersionUpdateListener versionUpdateListener) {
if (context == null || versionUpdateListener == null) {
throw new IllegalArgumentException(TAG + " : Context or VersionUpdateListener is null");
}
if (!INSTANCE.isInitialized) {
INSTANCE.initInternal(context, versionUpdateListener);
} else {
Log.w(TAG, "Init called twice, ignoring...");
}
}
private void initInternal(Context context, VersionUpdateListener versionUpdateListener) {
this.sharedPreferences = context.getSharedPreferences(PREFERENCES_APP_VERSION, Context.MODE_PRIVATE);
this.versionUpdateListener = versionUpdateListener;
this.isInitialized = true;
checkVersionUpdate();
}
private void checkVersionUpdate() {
int lastVersion = getLastVersion();
int currentVersion = getCurrentVersion();
if (lastVersion < currentVersion) {
if (versionUpdateListener.onVersionUpdate(currentVersion, lastVersion)) {
upgradeLastVersionToCurrent();
}
}
}
private int getLastVersion() {
return sharedPreferences.getInt(KEY_LAST_VERSION, 0);
}
private int getCurrentVersion() {
return BuildConfig.VERSION_CODE;
}
public void upgradeLastVersionToCurrent() {
sharedPreferences.edit().putInt(KEY_LAST_VERSION, getCurrentVersion()).apply();
}
public interface VersionUpdateListener {
boolean onVersionUpdate(int newVersion, int oldVersion);
}
}
use it on
public class MyApplication extends Application implements AppVersionUpgradeNotifier.VersionUpdateListener {
#Override
public void onCreate() {
super.onCreate();
AppVersionUpgradeNotifier.init(this,this);
}
#Override
public boolean onVersionUpdate(int newVersion, int oldVersion) {
//do what you want
return true;
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1.5b"
android:versionName="1.5b">
When you re-upload your app to Google Play, if these two attributes have been changed from the previous upload, Google Play will automatically send notifications to users who have installed your app. This is the AndroidManifest file.

Categories

Resources