[Plans] Integrate Google Store calls, and synch IAP with backend - step one#4078
[Plans] Integrate Google Store calls, and synch IAP with backend - step one#4078
Conversation
…e user could have cancelled them on the PlayStore). Re-synch purchases when the user buys a subscription from the store.
…ss-Android into feature/plans-integrate-store-step-one
Add comments.
…ss-Android into feature/plans-integrate-store-step-one
…ss-Android into feature/plans-integrate-store-step-one
…ss-Android into feature/plans-integrate-store-step-one
…ss-Android into feature/plans-integrate-store-step-one
…an subscription, and redirect the user to support. We're not going to enable upgrades whitin the apps.
…ss-Android into feature/plans-integrate-store-step-one # Conflicts: # WordPress/src/main/res/values/strings.xml
…lan attached to it.
…ss-Android into feature/plans-integrate-store-step-one
…ss-Android into feature/plans-integrate-store-step-one
|
I just tried this PR on a Nexus 6 emulator with the Google APIs, and at startup I'm seeing this: |
|
@nbradbury You should see a |
| final Plan plan = getPageAdapter().getPlan(position); | ||
|
|
||
| // No downgrade! | ||
| if (PlansUtils.isFreePlan(plan) || currentPlanProductId > plan.getProductID()) { |
There was a problem hiding this comment.
Rather than hard-code currentPlanProductId > plan.getProductID(), I think we should have a helper routine that checks if one plan is "greater" than another. We had this earlier on, and it was added to avoid sprinkling our code with assumptions that a greater plan ID meant a more expensive plan.
Introduce a utlity method that check if a plan is "greater" than another.
Fix a typo in the method that returns if a passed plan object is a free plan.
|
I'm wondering if we can make this more efficient. Every five minutes it makes a call to the IabHelper to get purchases (which by itself is fine since purchases are cached on the device), and then makes a separate POST to our backend for each purchase. This is fine for users who never buy anything since no network calls will be made, but otherwise it seems wasteful. I think we're okay decreasing the frequency of Even better would be some way to determine whether we even need to call our backend to update purchases, since the vast majority of the time our backend will already have the latest purchase info. This may seem like nitpicking since we're not talking about a huge waste of bandwidth, but over time I've seen us increase the number of network calls done at startup and at regular intervals, and I think we need to be more careful about unnecessary network usage. |
| return plan.getProductSlug().equals("free_plan") || | ||
| plan.getProductSlug().equals("jetpack_free"); | ||
| return plan.getProductSlug().equals(PlansConstants.FREE_PLAN_SLUG) || | ||
| plan.getProductSlug().equals(PlansConstants.JETPACK_FREE_PLAN_SLUG); |
Ok, will update the interval to 60 minutes, since it's already called at startup.
Yeah, I had thought to implement this kind of logic, but ended up with a code that was a bit clunky. We need to keep track if the purchase was already synched with the server, and keep track of server responses. Anyway, will try to rethink it. |
…not use scheduled updates, since the backend already synchs the IAPs nightly.
|
@nbradbury - This is ready for another round of review. |
Nevermind, I answered my own question by looking at your last commit. |
| public class UpdateIAPTask extends AsyncTask<Void, Void, Void> { | ||
| private static final int GET_IAP_BINDER_TIMEOUT = 30000; | ||
| private static final String IAP_ENDPOINT = "/iap/validate"; | ||
| protected Context mContext; |
There was a problem hiding this comment.
Minor nit, this can be private final rather than protected.
|
@nbradbury - I think all the issues brought up during the 2nd review are now resolved. |
|
|
||
| void logError(String msg) { | ||
| AppLog.d(AppLog.T.PLANS, "In-app billing error: " + msg); | ||
| AppLog.e(AppLog.T.PLANS, "In-app billing error: " + msg); |
There was a problem hiding this comment.
Both logError and logWarn are missing the mDebugLog check.
There was a problem hiding this comment.
The original version doesn't have the mDebugLog check for w and e logging. I think it's ok not having it there, since w and e are important.
|
|
This PR integrates Google Store calls into the app, and syncs in-app purchases with the backend.
In details:
Buybutton the app starts the Google Store purchase Intent.The
refreshtask, is something that syncs all the IAP info with the backend immediately after a purchase is made, at app startup, and every 5 minutes. This is just a security check, so we don't need to store in the app if the latest upgrades were synched with the server with success or not. Also, the user can cancel the subscription in the Google Store App, and we don't know this fact until the app is launched again (or the backend runs the nightly checks).This PR also disable
Buybutton if a paid plan is already available on the blog. Upgrades aren't handled in-app in this iteration.Note: Backend is not yet ready. You will see 404 errors on those network calls ;)