Many have asked for a way to support in app purchases. While everyone waits for the AG platform to offer a solution, I have been attempting to meet this need using PayPal. It’s a little clunky, but it seems to work. The beauty of this is it will allow your users to pay using PayPal, Venmo, or a credit card.
For those that might find this workaround useful, I’ll try to give a detailed description of how to build this into your app.
Concept Overview
- Your app will keep track if it’s the free version or paid version using a “paidApp” app variable
- paidApp variable will be saved (and loaded on app load) so this setting persists
- Premium features of your app will only function if paidApp variable is true
- When a premium feature is attempted when paidApp is false, the limitation is described and the user is presented with the option to pay to upgrade the app
- If user chooses to upgrade, a WebView is opened that presents PayPal button(s)
- The user clicks on the button and PayPal code takes over (for login, source of funds, etc.)
- When the payment completes successfully, an appgyver flow is triggered, which sets paidApp to true and saves this setting
- Now the app’s premium features will function without limitation
While this method could be duplicated to offer a number of upgrades for various premium features, for simplicity I’m going to describe a single purchase example for enabling all premium features with one purchase.
Prerequisites
This solution assumes you have the following:
- A PayPal account (I don’t think this needs to be a Business account, but not sure since that’s what I tested with)
- A place to host a couple of HTML files (your company web site)
- An AppGyver app with premium features that you want to cripple (or limit) until the user pays to upgrade
paidApp Variable
First we need to create the paidApp variable and manage the loading and saving of it. This is probably common knowledge for many of you, but in the interest of completeness, I’ll cover it here.
- Create an app variable called paidApp of type true/false (default is false)
- In Data tab, create a new Client-side storage resource called “settings”
- In addition to the default ‘id’ property, add another property called paidApp of type true/false
- In the Global canvas, create a flow on app launch to load the saved setting (or create it on the first launch)
This flow attempts to load the single record from the ‘settings’ resource (ID is appSettings or anything you like). If the initial attempt to get it fails (because it doesn’t yet exist), the 2nd block creates the record (custom object with ID=appSettings and Paid=false. Then we try to load the settings record again (as it should always succeed now). Then the last block sets the state of the paidApp app variable to the output of the previous block: Final Get Settings / Record: paidApp
- Also in the Global canvas, add another flow to handle saving the updated record if the paidApp variable is ever changed.
For the Update Record block, use the same ID as above (appSettings) and in the custom object, set paidApp to the current value of the app variable of the same name.
PayPal Developer Sandbox
To make it easier to test this functionality, create sandbox accounts (one for the user and one for you the merchant) using the PayPal Developer Dashboard. See docs about this. This will allow you to role-play paying with various payments sources, currencies, etc. to make sure everything works properly. Note the email address and password for the personal account, as this will be the credentials you use when testing how the user would pay for the app upgrade.
Next, visit My apps & credentials and create an app (in sandbox, not live), attaching it to the email address of the business sandbox account created above. Copy the long Client ID that is assigned to this app (you will need it later).
Hosted HTML Pages
You will need two pages to make this work. Working a bit backwards:
-
thanks.html – download here thanks.html (366 Bytes)
The content of this page isn’t really important as the user will never see this (if everything works).
Upload this file to the site where this will be hosted, and note the full URL to the file (as this will be needed later). -
upgrade.html – download sample here upgrade-sample.html (1.3 KB)
You will need to modify this file to suit your needs. At the very least, you need to modify the following:
- Customize & style the readable text: Upgrade app to Pro for only…
- Replace the YOUR_CLIENT_ID_HERE with the long string you copied from the sandbox app you created in your PayPal Developer Dashboard
- Edit the description “Upgrade MyApp to Pro” to better suit your app
- Edit {“currency_code”:“USD”,“value”:2.99} for the desired payment you wish
- Edit the URL http://yoursite.com/myapp/thanks.html to match the URL where you put the thanks.html file.
Rename this file (to remove -sample) and upload it to the site where this will be hosted, and note the full URL to it (as this will be needed later when you create the AppGyver upgrade page).
The style and various PayPal options embedded in this file may not suit your taste. Go to PayPal’s Button Factory to make your choices and have it spit out the code that you can place into this file.
Upgrade Page
Now that you have the HTML files that tie into PayPal’s button, you are ready to create the AppGyver upgrade page. This new page will only be visited when the user decides to pay for the app.
- Add a WebView component (from the component market) to this page. Feel free to style the page and the WebView size to taste and to match the rest of your app.
- Set the WebView’s URL to the full URL where your upgrade.html (you created above) is hosted
Note that I tried to use the HTML Content field rather than an externally hosted HTML file, but I couldn’t make this work for some reason. Too big??
Now add the following flow for the WebView.
This event is triggered whenever the WebView’s location changes. The first block checks to make sure that we’re at the thanks.html page (not the initial upgrade.html). It’s formula is: CONTAINS(outputs[“Receive event”].event.url, “thanks.html”)
The next block verifies that the transaction was actually completed. It does this by doing a cheesy split to get the status that follows the st= query in the redirect URL. This should really be doing query parsing, but this is okay since your upgrade.html file specifies the format of this (one and only) query. The formula is: SPLIT(outputs[“Receive event”].event.url,"=")[1] == "COMPLETED"
Once it makes it through these first 2 checks, you’re home free. The funds have been transferred and the flow now sets the paidApp variable to true (which automatically saves it in the global canvas). Then it navigates back to the page from which this upgrade page was entered.
Premium Features
Next, add the logic to cripple or limit one or more of your app’s premium features. The specifics of this will depend greatly on your app. A very simple example is a button that performs an action that is only supported when the user has paid for the upgrade.
Extremely simple example: a feature that can only be accessed if the app purchase has previously been made. The following flow controls access to the feature and will redirect to the upgrade process, if necessary.
A more complicated solution might involve allowing a user to take some action a limited number of times unless the app purchase has been previously made.
In this example, a counter allows something to occur up to 5 times, but after that the user is redirected to the upgrade path. To prevent being able to circumvent this by closing and reopening the app, this counter should probably be added to the settings schema and created/loaded/saved along with paidApp.
To make debugging of these premium feature enables easier, you might want to temporarily add a checkbox field somewhere in your app and bind it to the paidApp app variable. By directly controlling the paidApp variable, you can easily test your app’s behavior in the free and paid states. Don’t forget to remove this checkbox before distributing your final app
For extra finesse, you can style buttons based on the state of paidApp variable (for example, to show features ghosted out when paidApp == false).
Test!
Test, test, test! Take advantage of the sandbox and try paying for the upgrade in a number of ways. Using the PayPal developer portal, you can even simulate failed payments. Make sure everything responds properly. I accept no liability if this fails to collect money for you
Security
I’m unaware of a way for the app user to direct the WebView to a location of their choice. If there is a way, however, it would be pretty easy for them to spoof the logic described here and get an upgraded app without paying. There are ways to solve that, if so, but I didn’t complicate things with that on the assumption that the WebView is locked down. (Correct me if I’m wrong.)
Go Live
Now you’re ready to switch from the sandbox environment to the live environment.
- In the PayPal Developer Dashboard, create another app, this time selecting Live environment. This should be attached to your actual paypal account, rather than a sandbox account.
- Modify the Client ID value in your upgrade.html file to use the client ID for this live app (replacing the Client ID from the sandbox app)
- Upload the modified upgrade.html to the same place as before (overwriting the sandbox version)
No additional changes are needed to the AppGyver app to go live.
Maybe you will find this solution workable, at least until we have something better to use.