Android RealTimeMultiplayer onRoomCreated getting status 2 : STATUS_CLIENT_RECONNECT_REQUIRED - android

I am trying to setup realtime multiplayer in my Android Game. However, when I call Games.RealTimeMultiplayer.create(googleApiClient, roomConfig); after selecting the players.
However every time onRoomCreated is called with status STATUS_CLIENT_RECONNECT_REQUIRED and room null:
#Override
public void onRoomCreated(int statusCode, Room room) {
if (statusCode == STATUS_CLIENT_RECONNECT_REQUIRED) {
// This gets called repeatedly
reconnectGoogleLogin();
return;
} else if (statusCode != GamesStatusCodes.STATUS_OK) {
disableAlwaysOnScreen();
return;
}
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(
googleApiClient, room, MIN_NUMBER_OF_PLAYERS);
startActivityForResult(i, RC_WAITING_ROOM);
}
I have tried a number of things before asking this:
Yes I checked my Google Play Developer Console, the Realtime Multiplayer Settings is ON in the Linked Apps
The APK installed is with a valid sign key, I have the debug key-store as valid.
Looked through the documentation, but I couldn't figure out why this is happening.
Would love some help :)

Related

Drive AppFolder backups get lost

i`m using standard API (not REST API), and when i backup files and then restore, it works.... problems occurs when i re-install application. After re-install, files in AppFolder are not seen by app, but exists
Query query = new Query.Builder().addFilter(Filters.eq(SearchableField.TITLE, Tags.DB_DATA)).addFilter(Filters.eq(SearchableField.TRASHED, false)).build();
Drive.DriveApi.query(GAPI, query).setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
#Override
public void onResult(#NonNull DriveApi.MetadataBufferResult result) {
loadBackups(result.getMetadataBuffer());
result.release();
}
});
this is code so far (inside loadBackups im creating ArrayList with HashMap with details, nothing special), but i have tried listChildren and queryChildren, but same...
at certain point, it can be seen, but i did not catch when it happens, but i know for sure that after re-install, it can not be seen
Not enough rep to comment. However, I suspect that the issue you are having is that by design the last install of an app that a user has removes the app folder from Drive.
So your solution needs to be to back up to a place that is not owned by the app.
I've had a further issue on multiple installs where if you install the app on a second device, it takes "some time" (not sure how long) for Drive to propagate the app folder to the Drive. I have used this to sync data between devices but it is in the hands of Drive when the sync might work its way around.
try to put these line of code onConnected method,
try {
Drive.DriveApi.requestSync(mGoogleApiClient)
.setResultCallback(syncCallBack);
} catch (IllegalStateException ex) {
}
And then
private ResultCallback<Status> syncCallBack = new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (!status.isSuccess()) {
if (DriveStatusCodes.DRIVE_RATE_LIMIT_EXCEEDED == status.getStatusCode()) {
}
}
Query query = new Query.Builder()
.addFilter(Filters.contains(SearchableField.TITLE, "abc.txt"))
.build();
Drive.DriveApi.query(mGoogleApiClient, query)
.setResultCallback(metadataCallback);
}
};

Can't get Google Fit Recording API to work

I'm new to Android Wearable and Google Fit. I'm investigating how Google Fit Recording API works by creating a simple Android app with the following code in the Main Activity (these were taken from Google's Basic Recording API example):
#Override
protected void onCreate(Bundle savedInstanceState) {
...
buildFitnessClient();
}
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.RECORDING_API)
.addScope(Fitness.SCOPE_LOCATION_READ_WRITE)
.addScope(Fitness.SCOPE_ACTIVITY_READ_WRITE)
.addScope(Fitness.SCOPE_BODY_READ_WRITE)
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs. What to do?
// Subscribe to some data sources!
subscribe();
}
#Override
public void onConnectionSuspended(int i) {
// If your connection to the sensor gets lost at some point,
// you'll be able to determine the reason and react to it here.
if (i == ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
}
)
.enableAutoManage(this, 0, new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Google Play services connection failed. Cause: " +
result.toString());
Snackbar.make(
MainActivity.this.findViewById(R.id.main_activity_view),
"Exception while connecting to Google Play services: " +
result.getErrorMessage(),
Snackbar.LENGTH_INDEFINITE).show();
}
})
.build();
}
/**
* Subscribe to an available {#link DataType}. Subscriptions can exist across application
* instances (so data is recorded even after the application closes down). When creating
* a new subscription, it may already exist from a previous invocation of this app. If
* the subscription already exists, the method is a no-op. However, you can check this with
* a special success code.
*/
public void subscribe() {
// To create a subscription, invoke the Recording API. As soon as the subscription is
// active, fitness data will start recording.
// [START subscribe_to_datatype]
Fitness.RecordingApi.subscribe(mClient, DataType.TYPE_STEP_COUNT_DELTA)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
if (status.getStatusCode()
== FitnessStatusCodes.SUCCESS_ALREADY_SUBSCRIBED) {
Log.i(TAG, "Existing subscription for activity detected.");
} else {
Log.i(TAG, "Successfully subscribed!");
}
} else {
Log.i(TAG, "There was a problem subscribing: " + status.getStatusMessage());
}
}
});
// [END subscribe_to_datatype]
}
I wasn't sure how the recording API works. According to Google Fit documentation, the API would automatically take care of the tracking of steps (in this case) and storing the number of steps into the Fitness Store. So what I expected the app to work was starting the app, walking for a while, and when checking my Google Fit account, the number of steps should be increased.
However, this never occurred.
Could you please correct me if my understanding wasn't right, or if it is, please point me to the right direction to get this code working.
Cheers
Update: After more than an hour, my Google Fit data shown that the number of steps increased from 3033 (previously generated by the Fit app, which was then removed to securely testing this app) to 5011. The increasing amount is very confusing because I simulated steps by shaking my phone and certainly I didn't sake it 2000 times! I used Sensor API to display the number of steps in real time and the total of these numbers were only below 200.
Moreover, I manually checked the data every 10-20 mins and I'm sure that it took more than 1 hour for the data to get updated. According to Google Fit's documentation, the storing of data (into Fitness Store) is done automatically in a "battery- efficient manner". It however doesn't mention clearly how that is done, i.e., how frequently.
It would be great if someone can help me with these questions. Any help appreciated!
Can you filter it by using the confidence level for each activity?
eg.
An example of the values for a likely detection of walking may be:
walking -> 20.0
in_vehicle -> 10.0
biking -> 66.6

Google play services doesnt displays leaderboard after Auth

Its a very weird have invested a lot of time in this. So asking here.
I am using this plugin and followed the steps https://github.com/playgameservices/play-games-plugin-for-unity
I just want to use Google play services in release mode for leaderboard only (i am using in alpha launch)
Here is my code for Auth in GPlay services :
void Awake(){
PlayerPrefs.SetInt("GameOverCount",0);
#if UNITY_ANDROID
Authenticate ();
#endif}
I have configured Gplay setup by providing 10+ digit Client ID
I have generated OAuth Client ID from Google APis using SHA1 of release.keystore that i am using.
In Gplay service in DEveloper console : I have published the linked apps without any errors
public void Authenticate() {
if (Authenticated || mAuthenticating) {
Debug.LogWarning("Ignoring repeated call to Authenticate().");
return;
}
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
.EnableSavedGames()
.Build();
PlayGamesPlatform.InitializeInstance(config);
// Activate the Play Games platform. This will make it the default
// implementation of Social.Active
PlayGamesPlatform.Activate();
// Set the default leaderboard for the leaderboards UI
((PlayGamesPlatform) Social.Active).SetDefaultLeaderboardForUI(leaderboardID_android);
// Sign in to Google Play Games
mAuthenticating = true;
Social.localUser.Authenticate((bool success) => {
mAuthenticating = false;
if (success) {
UnityAnalytics.CustomEvent("Auth Completed", new Dictionary<string, object>
{
{ "isAuthDone", true }
});
if(showScores){
Social.Active.ShowLeaderboardUI();
Debug.Log("should show leaderborad");
}
// if we signed in successfully, load data from cloud
Debug.Log("Login successful!");
} else {
// no need to show error message (error messages are shown automatically
// by plugin)
Debug.LogWarning("Failed to sign in with Google Play Games.");
UnityAnalytics.CustomEvent("Auth Failed", new Dictionary<string, object>
{
{ "isAuthDone", false }
});
}
});
}
#if UNITY_ANDROID
if (Authenticated) {
showScores = false;
((PlayGamesPlatform)Social.Active).ShowLeaderboardUI(leaderboardID_android);
Social.ShowLeaderboardUI();
Debug.Log("should show leaderborad");
UnityAnalytics.CustomEvent("Authenticated and show android leaderboard", new Dictionary<string, object>
{
{ "isShowing", true }
});
}else{
showScores = true;
Authenticate();
}
#endif
Next, i release the alpha and check on android devices - i get a screen saying connecting to google play games...connects processes and then goes off the screen.
It seems like it authenticates and goes off. But doesn't displays leaderboard for some reason. I am not able to understand why its happening and what's missing.
In my unity analytics, only once scores aren't loaded and i played it 20-30 times :
In my Developer console, Number of scores is empty :
Can anybody pls help in this, i can provide more details to people who can help / want to help....Thanks...

Google in app purchase and cracking

i developed an app that's become very popular and someone cracked it. I would like to know if someone know, first of all: how?, if someone know any workaround to avoid this. The app is using the in-app purchase as per google example to unlock some premium features in this way:
private IabHelper mHelper;
if (!isPro(getActivity())) {
mHelper = new IabHelper(getActivity(), KKK);
mHelper.enableDebugLogging(true);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
return;
}
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
// IAB is fully set up. Now, let's get an inventory of stuff we own.
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
// Is it a failure?
if (result.isFailure()) {
return;
}
Purchase pro = inventory.getPurchase(PRO_STRING);
SettingsProvider.putSecBoolean(getActivity(), "pro", pro != null && verifyDeveloperPayload(pro));
}
};
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
if (mHelper == null) return;
if (result.isFailure()) {
return;
}
if (purchase.getSku().equals(PRO_STRING)) {
SettingsProvider.putSecBoolean(getActivity(), "pro", true);
}
}
};
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
return true;
}
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null) {
mHelper.dispose();
mHelper = null;
}
}
and for the purchase process:
mPro.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RandomString randomString = new RandomString(36);
String payload = randomString.nextString();
if (mHelper != null) mHelper.flagEndAsync();
mHelper.launchPurchaseFlow(getActivity(), PRO_STRING,
IabHelper.ITEM_TYPE_INAPP, RC_REQUEST,
mPurchaseFinishedListener, payload);
}
});
Ok, someone in someway cracked it. This means the content available in the pro version are free without paid. Maybe someone can share his experience and suggest some way to avoid this?
And also, does anyone know how can that be done? Thanks
Brief explanation
Android applications are quite easy to crack. First of all, if you are not using any obfuscation on your code (ProGuard, DexGuard, ..), the code can be easily read and understood by using some tools like JD-GUI. In some cases, the smali code is pretty easy to understand as well.
The obfuscation itself won't save you from cracking. There are de-obfuscators available on the market, but someone with a high pitched reverse engineering skill will still be able to figure out how to bypass your (or Google's) protection.
Finally, there is LuckyPatcher. This is perhaps the most famous tool for cracking Android apps' protection. It targets specifically certain types of protections (Google's LVL, IAPs, advertising networks, ..) and tries to remove them on a statistical basis. In fact, it is not guaranteed 100%, but in the vast majority of cases it will work just fine.
How to be secure, then?
You simply can't. There is no perfect 100% security, especially in a mobile environment. What you can do, however, is trying to make a cracker's work as difficult as possible.
A few ideas:
Always obfuscate. It won't do any damage to your app (if configured correctly), and it will be yet another layer of protection to your code.
Use DexGuard's tampering detection function. It will definitely decrease the chances that your app gets cracked two days after an update is released.
There are a few more, I will add them as soon as I recall them all.
Your code is really simple to crack, you just need to replace
SettingsProvider.putSecBoolean(getActivity(), "pro", pro != null && verifyDeveloperPayload(pro));
with:
SettingsProvider.putSecBoolean(getActivity(), "pro", true);
It can be done in several ways as antilvl does for example. You need to increase your protection a lot maybe with cross-check of your own server.

In-App Billing test: android.test.purchased already owned

I am currently testing In-App Billing for a future app, and after I successfully "bought" the test item "android.test.purchased" the first time, I now receive the response code 7 every time I try to buy it again, which means that I already own this item.
12-15 23:02:14.149: E/IabHelper(19829): In-app billing error: Unable
to buy item, Error response: 7:Item Already Owned
From what I understand, this purchase is supposed to always be possible, right? So that the developer can test his/her app?
If not, how can I "reset" its state to not owned? I am using the util package from the Google In-App Billing Sample.
Add this code to a thread to initiate consume request.
int response = mService.consumePurchase(3, getPackageName(), purchaseToken);
Here for the purchase test, purchaseToken is
purchaseToken = "inapp:" + getPackageName() + ":android.test.purchased";
And
if (response == 0)
then the consumption is successful.
also don't forget to make mService public in
IabHelper.Java
then it would be possible to access like this:
int response = mHelper.mService.consumePurchase(3, getPackageName(), purchaseToken);
No need to write any special consumption code. Just use the adb command for clearing the Google Play Store data:
adb shell pm clear com.android.vending
It turns out that the android.test.purchased item behaves like a regular ID. It means that if you want be able to buy it again, you have to consume it somewhere in your code. I think that the Google documentation is misleading on this matter, and that they should add another static ID that you can buy endlessly for test purposes.
In-app version 3:
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
.....................
if (inventory.hasPurchase(SKU_CONTENT)) {
mHelper.consumeAsync(inventory.getPurchase(SKU_CONTENT), null);
}
}
};
Version 3 - Fastest way to solve : Clearing the cache of Google Play Store will let "android.test.purchased" available again.
This is how we can consume the Item
consume.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
String purchaseToken = "inapp:" + getPackageName() + ":android.test.purchased";
try {
Log.d("","Running");
int response = mService.consumePurchase(3, getPackageName(), purchaseToken);
if(response==0)
{
Log.d("Consumed","Consumed");
}else {
Log.d("","No"+response);
}
}catch (RemoteException e)
{
Log.d("Errorr",""+e);
}
}
});
t.start();
}
});
In my opinion if your program is not designed to consume the item you do not need to tweak the code in order to clear the memory of an outside vendor. This will make your code more fragile and you will have then to spend a lot of time to add and remove code that does not belong to your software so it is a bad design to implement a solution like that.
The best solution that worked for me to clear android.test.purchased was
adb uninstall com.yourapp.name
and then
adb shell pm clear com.android.vending
I did not need to clear cash and to browse my apps setting or to change code for that. I did need to add the adb to path variables of windows system which was pretty straight forward. So yes you need to use adb which you probably need anyway so..
You just add your C:\ ...\android-sdk\platform-tools; in windows path in environment variables, and I imagine that it is pretty simple in mac and linux os as well. Hope it helps someone to spend few days less with implementing android in app billings.
Go to the Google Play Developer Console, open Order Management menu item from the left side and select the order you want to refund. Also make sure to remove the entitlement.
The main issue is you have to consume the android.test.purchased item. But this item won't be available in your query inventory, so you can't consume using the normal flow.
So, if you are using IabHelper, in IabHelper class, you can temporarily change the IInAppBillingService mService to public so that it is accessible from your IabHelper.
Then in your class, you can consume like this,
int response = mHelper.mService.consumePurchase(3, getPackageName(), "inapp:"+getPackageName()+":android.test.purchased");
If success, the response is going to be 0.
Hope this helps.
For testing purposes I also suggest you to insert a piece of code that will be clearing all the products that you've bought before calling a method that initializes gp purchase flow. That is especially comfortable, when you test just one item at the moment. E.g. like this:
PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
for (Purchase sourcePurchase : purchasesResult.getPurchasesList()) {
if(sourcePurchase != null){
ConsumeResponseListener listener = new ConsumeResponseListener() {
#Override
public void onConsumeResponse(String outToken, #BillingResponse int responseCode) {
System.out.println("all consumed");
}
};
mBillingClient.consumeAsync(sourcePurchase.getPurchaseToken(), listener);
}else{
System.out.println("null");
}
}
// and then initiate whole process with clear "shoping basket"
BillingFlowParams.Builder builder = new BillingFlowParams.Builder()
.setSku(itemName).setType(BillingClient.SkuType.INAPP);
If you are in test environment
1) In the case of android.test.purchased, I can reset the fake payment by restarting android device(consumed the inventory).
2) In InApp util there is a file called Security.java make it as following, for temporary. Since the testing payment(fake) always return false due to security exception.
public static boolean verifyPurchase(String base64PublicKey,
String signedData, String signature) {
return true; }
Then in your OnIabPurchaseFinishedListener call fechInvForconsumeItem()
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,
Purchase purchase)
{
if (result.isFailure()) {
// Handle error
Log.e("123","Failure");
return;
}
else if (purchase.getSku().equals(ITEM_SKU)) {
Log.e("123","PURCAsed");
fechInvForconsumeItem(); // Restart device if not consume
}
}
};
The fechInvForconsumeItem() is
public void fechInvForconsumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// Handle failure
Log.e("11","Failure");
} else {
Log.e("11","suc");
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU),
mConsumeFinishedListener);
}
}
};
Consume Listener is
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase,
IabResult result) {
if (result.isSuccess()) {
} else {
// handle error
Log.e("11","sucConsume");
}
}
};
IabHelper.QueryInventoryFinishedListener
mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if (result.isFailure()) {
return;
}
try {
if(inventory.hasPurchase("product_sku_id"))
{
isItemEnable= true;
mHelper.consumeAsync(inventory.getPurchase("product_sku_id"),null);
}
else
{
isItemEnable = false;
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
In my case, it appears that Google does not record a purchase for the item. Rather, the local copy of Google Play Services caches the purchase. That way, when a second request is made on the same device, android.test.purchased already owned appears. However, using another device or resetting the device clears the cache, and allows the purchase to be repeated.
In my case, I just needed to clear the apps cache. After clearing the cache, I was able to initiate the purchase flow again.
From my device (4.4.2), I navigated to "Settings->Application manager". Next, I selected the app from the "DOWNLOADED" tab, and then "Clear cache".
This is the difference between consumable and non-consumable items; non-consumable items (what you seem to be dealing with here) have their state tracked persistently, while consumable items can be purchased multiple times. You'll have to go into your Play management console and cancel/refund the sale to test it again.

Categories

Resources