dotnet / android-libraries

.NET for Android bindings for Google's libraries, such as AndroidX, GooglePlayServices, Firebase, and MLKit and their 3rd party dependency libraries.
MIT License
236 stars 50 forks source link

Android.Gms.PlayGames.GetPlayersClient and PlayersClient API Missing from Xamarin.GooglePlayServices.Games.V2 #975

Open stuartmilleruk opened 1 year ago

stuartmilleruk commented 1 year ago

Xamarin.Android Version (eg: 6.0): net7.0-android32

Operating System & Version (eg: Mac OSX 10.11): MacOS Ventura 13.1

Google Play Services Version

Describe your Issue

Some of the Google PlayGames V2 API appears to be missing in the nuget packages, which makes it tricky to support basic usage of the PlayGames V2 API. The main issue is that there doesn't appear to be any binding for the PlayersClient part of the API, which means there's no way of getting the players display name or any information about the currently signed in player.

My main use-case is : If a user changes their Google Play profile in the OS Settings, there doesn't seem to be a way to identify that the player that is now automatically signed in by the app with PlayGames.V2 is different or has changed... so there's no way for the app to, for example, invalidate any cached data that was in-use with a previous PlayGames user.

As an example, the Google PlayGames V2 docs show one usage that doesn't appear to be possible with Xamarin, because there's no getPlayersClient call available ( unlike, for example, the GetAchievementsClient() call which is exposed ). Having that API available would make my particular use case possible.

PlayGames.getPlayersClient(activity).getCurrentPlayer().addOnCompleteListener(mTask -> {
    // Get PlayerID with mTask.getResult().getPlayerId()
  }
);

( taken from : Play Games v2 Sign in Documentation )

Are there any plans to add this functionality, or is there a workaround that can be used to identify the user or extract this information? I'm not too familiar with the way Xamarin binds to the platform api's so haven't been able to add this functionality successfully myself yet.

pekspro commented 1 year ago

I'm also missing this.

stuartmilleruk commented 11 months ago

@pekspro were you able to find a workaround for this? I'm now coming back around to this issue hoping there might have been a fix or a workaround, but there doesn't seem to have been any movement on it so far.

@jpobst If this is something we'd be able to add to the binding, then any information on how would be great. I'm not sure how the bindings are generated for the GooglePlayServicesComponent, but if it's just a case of inserting some metadata for the function somewhere and rebuilding, then it might be something I could do.

pekspro commented 11 months ago

@stuartmilleruk, thanks, no I did not found any workaround for this issue. A solution for this and https://github.com/xamarin/AndroidX/issues/972 woule be highly appreciated :-)

stuartmilleruk commented 6 months ago

I've recently come back onto this task as I didn't make any progress figuring out how to add new endpoints and noticed a new version of the GooglePlayServices bindings were released ( but still missing the bindings to get the current player to know who is signed in or if the user has changed whilst the app is suspended )

@pekspro Did you get any further or figure out a workaround?

pekspro commented 6 months ago

@stuartmilleruk, no, I'm still stuck on this. Also, the new version doesn't compile with .NET 8 for some reason :-(

stuartmilleruk commented 4 months ago

@moljac I saw there was some progress with the other related task with the PlayGames.V2 bug @ https://github.com/xamarin/AndroidX/issues/972

Do you know if the fix that's planned for that one will also fix this one and what the pull request was?

If not ( or even if it does ) ... I don't supposed you know of a workaround to get access the the PlayGames.V2 PlayerID? I pretty much just need access to that alone and I'm happy to use a workaround if there's a way of directly patching into the PlayGames.getPlayersClient().getCurrentPlayer().getPlayerID() call.

Just a bit stuck knowing where to start as I've not done any C# -> Java binding, or if there's some sort of Reflection API available in .NET C# for directly calling the Java platform APIs ( even if a bit hacky ).

stuartmilleruk commented 3 months ago

So I started building and figuring out the bindings to see if I could make some progress with this, but not making a lot of progress mainly because I'm trying to figure out how the whole binding system works with Xamarin and I'm far from an expert ( games consoles, I'm an expert ... Xamarin Android, not so much yet! )

so far, I think the issue is related to these warnings when building the bindings ( i.e. dotnet cake -t=binderate followed by dotnet cake -t=nuget )

warning BG8801: Invalid parameter type 'com.google.android.gms.games.Player' for member 'Android.Gms.Games.IPlayersClient.GetCompareProfileIntent (Android.Gms.Games.IPlayer)'. warning BG8503: Invalidating 'Android.Gms.Games.IPlayersClient' and all its nested types because some of its methods were invalid. warning BG8701: Invalid return type 'com.google.android.gms.games.PlayersClient' for member 'Android.Gms.Games.PlayGames.GetPlayersClient (android.app.Activity)'. warning BG8102: Class 'Android.Gms.Games.PlayerRef' has unknown base type 'com.google.android.gms.games.zzo' warning BG8102: Class 'Android.Gms.Games.GameRef' has unknown base type 'com.google.android.gms.games.zzo'

I've got a hunch it all starts with that com.google.android.gms.games.zzo reference, but haven't figured out where it needs to be added or fixed up.

Looking in

play-services-basement/Transforms/Metdata.xml

I can see a line that says

<remove-node path="/api/package/class[contains(@name, 'zz') and @name != 'Api.zza' and @name != 'zzf' and @name != 'zzc' and @name != 'zzd' and @name != 'zza' and @name != 'zzg' and @name != 'zzb' and @name != 'zzp' and @name != 'zzbgl' and @name != 'zzs']" />

.. so I tried adding it there, but no change.

@moljac if you've got any tips on where to start and what I'm looking for, then that'd be awesome and would save me digging around. I'm happy to have a go at at least fixing up the PlayersClient bit ( as mentioned in previous post, I just need the getPlayersId() call to help me towards adhering to the google continuity requirements https://developer.android.com/games/playgames/continuity-requirements as well as the original issue of tracking when a user has changed ), but if I can figure out more then I'll obviously share back.

stuartmilleruk commented 3 months ago

Continued trying to find my way around the binding system and I think I might have made some progress ( although it's slow without any docs! ).

Story so far..

Right now, I'm aiming to try to remove this error:

api.xml(406,6): Warning BG8503 : Invalidating 'Android.Gms.Games.IPlayer' and all its nested types because some of its methods were invalid.
Xamarin.Android.Bindings.Core.targets(99,5): Warning BG8503 : Invalidating 'Android.Gms.Games.IPlayer' and all its nested types because some of its methods were invalid.

With the thinking being that if I can solve that one, then maybe it will fix the errors related to com.google.android.gms.games.player being invalid like this one:

api.xml(606,10): Warning BG8801 : Invalid parameter type 'com.google.android.gms.games.Player' for member 'Android.Gms.Games.IPlayersClient.GetCompareProfileIntent (Android.Gms.Games.IPlayer)'.
Xamarin.Android.Bindings.Core.targets(99,5): Warning BG8801 : Invalid parameter type 'com.google.android.gms.games.Player' for member 'Android.Gms.Games.IPlayersClient.GetCompareProfileIntent (Android.Gms.Games.IPlayer)'.

Above the "Invalidating.." error, there were lots of errors referencing zzo,zzh and zza classes that were missing and after adding:

 <attr path="/api/package[@name='com.google.android.gms.games.internal.player']/class[@name='zza']" name="obfuscated">false</attr>
 <attr path="/api/package[@name='com.google.android.gms.games']/class[@name='zzo']" name="obfuscated">false</attr>
 <attr path="/api/package[@name='com.google.android.gms.games.internal']/class[@name='zzh']" name="obfuscated">false</attr>

to the Metadata.xml file of the play-services-games-v2 bindings I was able to get it down to this one error that was above that "Invaliding..." error line:

api.xml(435,8): Warning BG8700 : Unknown return type 'com.google.android.gms.games.internal.player.zza' for member 'Android.Gms.Games.IPlayer.Zzc ()'.
Xamarin.Android.Bindings.Core.targets(99,5): Warning BG8700 : Unknown return type 'com.google.android.gms.games.internal.player.zza' for member 'Android.Gms.Games.IPlayer.Zzc ()'.

And this is where I'm stuck.

I'm thinking that if I can just remove the bindings for that IPlayer::Zzc member, then maybe that'll be enough for now and I don't think I need it or most of this stuff. Looking in the api.xml file that's generated I can see this bit of binding

<interface abstract="true" deprecated="not deprecated" final="false" name="Player" static="false" visibility="public" jni-signature="Lcom/google/android/gms/games/Player;">
<method abstract="true" deprecated="not deprecated" final="false" name="zzc" jni-signature="()Lcom/google/android/gms/games/internal/player/zza;" bridge="false" native="false" return="com.google.android.gms.games.internal.player.zza" jni-return="Lcom/google/android/gms/games/internal/player/zza;" static="false" synchronized="false" synthetic="false" visibility="public" />

which i think is the line that it's got a problem with.

I can see you can put tags into the metadata.xml for the bindings, but I'm not sure how if or how I'd make a line that would strip that Zzc() method out.

I found this link

https://developer.xamarin.com/guides/android/advanced_topics/binding-a-java-library/troubleshooting-bindings/#Problem_Missing_C_types_in_generated_output in issue https://github.com/xamarin/GooglePlayServicesComponents/issues/206

but the link is dead. I found an old version from back in 2018, though, but it didn't really get me any further.

Does anyone know if there's a way to strip this out? Or if there are any docs for any of this stuff?

pekspro commented 3 months ago

@stuartmilleruk, I have no useful information, and don't have any time to do any contribution. I just wanted to say I'm very, very impressed by your ambition 🙂.

stuartmilleruk commented 3 months ago

@pekspro thanks :)

I've just figured out if I also add:

<remove-node path="/api/package[@name='com.google.android.gms.games']/interface[@name='Player']/method[contains(@name, 'zzc')]" />
<remove-node path="/api/package[@name='com.google.android.gms.games']/class[@name='PlayerEntity']/method[contains(@name, 'zzc')]" />
<remove-node path="/api/package[@name='com.google.android.gms.games']/class[@name='PlayerRef']/method[contains(@name, 'zzc')]" />

It stops the binding generator from removing the IPlayer and Player interfaces and generates the bindings for them ( or that's what I think it's done! ).

So I'm now into the .cs compilation phase of the bindings, but with lots and lots of errors which I'm now working through.

I'll update here again when I make some more progress. Currently I have no idea if any of this is actually going to work, of course or if I'm going on a wild goose chase.

stuartmilleruk commented 3 months ago

Quick update... I've got the PlayerClient bindings to compile and work! I'm now able to get the PlayerId in my android app :)

Unfortunately, I've run out of time for today, but next week I'll prep a pull request with my changes in. It's going to be a bit complicated as I'm a few revisions behind ( I'm on commit 3b0d874 ) so it's going to take me a bit of time to clean things up and update.

@pekspro my changes also appear to have all the interfaces bound for the SnapshotClient too. But, I've barely tested the PlayersClient so have no idea if they work .. this is all very bleeding edge as of around 10 minutes ago.

If there's a quicker way to get the changes over that can make integration a bit faster, then let me know. I'm happy to just attach the changed files/diffs if it will speed up the process ( I'll be the first to admit, I'm more of a Perforce user than a git user so I've got to remember how to actually do a pull request on github again )