I have implemented in app billing in a game. We are using unity3d as our game development engine . For in app billing to work I wrote a java native plugin that handles in app billing jobs and send messages back to unity application when purchase is done.
The way I implemented this is to start another activity to handle billing tasks and finish that activity after the tasks are done to return to unity app. But the problem is that in some devices(specially with low RAM) the unity app get closed when the billing activity is started . So when the user purchase an item our listeners in unity app are no longer valid and the unity app is restarted. We can't give them the item which is bought (It's consumed).
So my question is that is there any way to force the unity app remain untouched while the billing activity is running ?
My Code that fires billing activity:
public static void Buy(String SKU,String developerPayLoad,boolean Consumable)
{
Intent buyIntent = new Intent(gameActivity,MyketActivity.class);
buyIntent.putExtra("OPERATION", "PURCHASE");
buyIntent.putExtra("SKU", SKU);
buyIntent.putExtra("PayLoad", developerPayLoad);
buyIntent.putExtra("Consumable", Consumable);
gameActivity.startActivityForResult(buyIntent, 8586);
}
//The billing activity's OnCreate
protected void onCreate(Bundle bundle)
{
String Operation = getIntent().getStringExtra("OPERATION");
super.onCreate(bundle);
if(!FirstTime)
{
MyketHelper.Log("Not for the First Time");
finish();
return;
}
if(Operation.equals("PURCHASE"))
{
if(MyketHelper.helper==null)
{
finish();
return;
}
MyketHelper.Log("Purchase Flow Launched");
SKU = getIntent().getStringExtra("SKU");
PayLoad = getIntent().getStringExtra("PayLoad");
Consumeable = getIntent().getBooleanExtra("Consumable", true);
MyketHelper.helper.launchPurchaseFlow(this, SKU, 8585, OnPurchase);
}
}
Related
Recently I tested 'deferred deeplink' function by using facebook SDK.
But there is one problem.
# I did it.
First, I have completed all of setting for apps by using the "App Ads Helper" function from developers.facebook.com.
https://developers.facebook.com/tools/app-ads-helper
Second, so I obtained the good result by using "DeepLink Test" provided by"App Ads Helper".
And I could see what i want (AppLinkData)
06-04 12:58:25.598 11903-11925/? I/DEBUG_FACEBOOK_SDK﹕ Bundle[{com.facebook.platform.APPLINK_NATIVE_CLASS=, target_url=myapp://myapp.co.kr?test=1111, com.facebook.platform.APPLINK_NATIVE_URL=myapp://myapp.co.kr?test=1111}]
Third, here is the code what I used.
protected void onCreate(){
....
FacebookSdk.sdkInitialize(getApplicationContext());
AppLinkData.fetchDeferredAppLinkData(getApplicationContext(),
BSTracker.getInstance().getFacebookIdMeta() ,
new AppLinkData.CompletionHandler() {
#Override
public void onDeferredAppLinkDataFetched(AppLinkData appLinkData) {
if (appLinkData != null) {
Bundle bundle = appLinkData.getArgumentBundle();
Log.i("DEBUG_FACEBOOK_SDK", bundle.toString());
} else {
Log.i("DEBUG_FACEBOOK_SDK", "AppLinkData is Null");
}
}
});
}
Finally. This is My App Setting
Ad Setting
It is My Ad setting.
i did input the DeepLink in "Get install of your App" Ad Product.
# Problem
When I created commercial ad at Facebook and released for the audience but I can't get Deferred DeepLink.
Please let me know, anything is wrong with it.
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...
I have inAppBilling working but i'm trying to refine it a little bit. I noticed that when I try in app billing in Angry Birds it opens directly on top of the application but my application pulls in app billing to the foreground/desktop. I read the docs and it states that singleTop must be off and reflection must be used as well with an activity context given and NOT an application context. I have verified that I have all of those things done but its still pulling to the foreground. Any ideas?
My verification:
I have an activity called MyActivity
Log.d("TEST", mContext.getClass().getName());
responds back with MyActivity
and in Android Manifest for MyActivity
android:launchMode="standard"
EDIT:
The code that starts the checkout activity
void startBuyPageActivity(PendingIntent pendingIntent, Intent intent) {
if (mStartIntentSender != null) {
// This is on Android 2.0 and beyond. The in-app buy page activity
// must be on the activity stack of the application.
try {
// This implements the method call:
// mActivity.startIntentSender(pendingIntent.getIntentSender(),
// intent, 0, 0, 0);
mStartIntentSenderArgs[0] = pendingIntent.getIntentSender();
mStartIntentSenderArgs[1] = intent;
mStartIntentSenderArgs[2] = Integer.valueOf(0);
mStartIntentSenderArgs[3] = Integer.valueOf(0);
mStartIntentSenderArgs[4] = Integer.valueOf(0);
mStartIntentSender.invoke(mActivity, mStartIntentSenderArgs);
Log.d("TAG", mActivity.getClass().getName());
} catch (Exception e) {
Log.e(TAG, "error starting activity", e);
}
} else {
// This is on Android version 1.6. The in-app buy page activity must be on its
// own separate activity stack instead of on the activity stack of
// the application.
try {
pendingIntent.send(mActivity, 0 /* code */, intent);
} catch (CanceledException e) {
Log.e(TAG, "error starting activity", e);
}
}
}
What I am trying to accomplish is for the in app billing prompt whether it finishes the transaction or cancels to resume back to my game instead of simply closing and finishing. A current fix I have is to start the games Activity again which would result in reloading everything and putting the player back at the main menu page.
In my application I have used some code from the iosched 2012 app. In specific the starting workflow is the following:
1.The user presses the launcher icon of the app
2.HomeActivity checks if the user is authenticated. If he/she is not, it starts the Authentication activity, passing it intent to it and finishes itself
3.When the login process is successful, the authenction activity starts an activity in order to start the HomeActivity and finishes itself
4.HomeActivity checks again if the user is authenticated and displays the home screen of the application.
The following code works like a charm in API Level > 11. Today, I tried the app in a Gingerbread and it fails. Step 3 works, but although the HomeActivity starts it's not brought to front. You have to use the recent list and choose the application in order to see the homeactivity and its now displayed content.
Here's the code and check from the HomeActivity in the oncCreate method
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!AccountUtils.isSystemAuthenticated(this)) {
AccountUtils.startSystemAuthentication(this, getIntent());
finish();
} else if(!AccountUtils.isAppAuthenticated(this)) {
AccountUtils.startAppAuthentication(this, getIntent());
finish();
}
if(isFinishing()) {
return;
}
setContentView(R.layout.activity_main);
...
}
}
The method invoked in the Authentication activity after the login process is completed
protected void handleLoginSuccess(LoginServiceResponse response, String username, String password) {
if(....) {
if(mFinishIntent != null) {
mFinishIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mFinishIntent.setAction(Intent.ACTION_MAIN);
mFinishIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(mFinishIntent);
}
finish();
} else {
super.handleLoginSuccess(response, username, password);
}
}
Where the mFinishIntent member variable is the intent passed from the HomeActivity (using getIntent())
As I mentioned, in API Level > 11, this works well, and the breakpoint in HomeActivity's onCreted method is hit twice, while in a Gingerbread phone, is hit only once (only when the application starts).
Do I have to use another flag or do you have any other idea of what's going on?
Thanks
What is probably happening is that the activity is only created when the app is started and then when you go back to it from the Authentication activity, it is simply resumed. Try putting the authentication checking code in HomeActivity in the onResume() method.
Here is some more info: http://developer.android.com/reference/android/app/Activity.html#ProcessLifecycle
I'm using the In App Billing sample app to add this feature to my application.
After I finished adding it to my app, and tested all working, I noticed the comment in this Security class:
Security-related methods. For a secure implementation, all of
this code should be implemented on a server that communicates with
the application on the device. For the sake of simplicity and
clarity of this example, this code is included here and is executed
on the device. If you must verify the purchases on the phone, you
should obfuscate this code to make it harder for an attacker to
replace the code with stubs that treat all purchases as verified.
As Google suggests, I do the purchase verification on the server side so I really don't need the Security class in my project.
The problem is, I can't figure out how to remove the BillingService class dependency in the Security class.
I started by deleting the Security class and following the errors in the BillingService and most places it's being used I can remove easily, except in one place:
private void purchaseStateChanged(int startId, String signedData, String signature) {
ArrayList<Security.VerifiedPurchase> purchases;
purchases = Security.verifyPurchase(signedData, signature);
if (purchases == null) {
return;
}
ArrayList<String> notifyList = new ArrayList<String>();
for (VerifiedPurchase vp : purchases) {
if (vp.notificationId != null) {
notifyList.add(vp.notificationId);
}
ResponseHandler.purchaseResponse(this, vp.purchaseState, vp.productId,
vp.orderId, vp.purchaseTime, vp.developerPayload);
}
if (!notifyList.isEmpty()) {
String[] notifyIds = notifyList.toArray(new String[notifyList.size()]);
confirmNotifications(startId, notifyIds);
}
}
Would love if someone can share his/hers purchaseStateChanged method (based on the in app billing sample app) without the use of the Security class.
So here's what I did. First the calls to BillingService occur on the applications main thread, so you need to issue your server calls in a background thread. I chose to finish up processing on the main thread, since I wasn't sure what impact calling methods like 'confirmNotifications' on a background thread might have.
I created a callback interface VerifyTransactionCompletion which could be dispatched back to the main thread after the remote call completed.
I keep around the Security class and have it manage the call to the server now, instead of what it originally performed in the sample. So when you see the call to Security, that's where I call out to my server and perform signature validation.
/**
* Callback interface to <em>finish</em> processing a transaction once the remote
* servers have processed it.
*/
public interface VerifyTransactionCompletion {
public void transactionVerified(List<Security.VerifiedPurchase> purchases);
}
private void purchaseStateChanged(final int startId, String signedData, String signature) {
// verifyPurchase issues remote call to server (in a background thread), then
// calls transactionVerified on the main thread to continue processing.
Security.verifyPurchase(signedData, signature, new VerifyTransactionCompletion() {
#Override
public void transactionVerified(List<VerifiedPurchase> purchases) {
if (purchases == null) {
return;
}
ArrayList<String> notifyList = new ArrayList<String>();
for (VerifiedPurchase vp : purchases) {
if (vp.notificationId != null) {
notifyList.add(vp.notificationId);
}
ResponseHandler.purchaseResponse(BillingService.this, vp.purchaseState, vp.productId,
vp.orderId, vp.purchaseTime, vp.developerPayload);
}
if (!notifyList.isEmpty()) {
String[] notifyIds = notifyList.toArray(new String[notifyList.size()]);
confirmNotifications(startId, notifyIds);
}
}
});
}