Documente Academic
Documente Profesional
Documente Cultură
1
Introduction
2
Introduction
4
Duration: 1hr Getting Started
Goal: Build an Android • Beginner experience with Android/ Amazon Fire Tablet (2015+) or an
Java development Android device (Android 5+ Lollipop
app that implements required) with developer options
quarterly and monthly • Laptop (Win/Mac/Linux) turned on, and all the Android
subscriptions to a magazine • Install Android Studio (version 3.0.1+)
Debug Bridge tools installed, along
with the device drivers.
using the Amazon In-App
• Install Amazon Appstore on your
Purchase SDK. device (if Android device)
5
Step 1:
6
Unzip the SDK and open
InAppPurchasing folder
This folder contains the IAP SDK, IAP
Coding Samples and a test JSON file
that we are going to use later on.
7
Step 2:
• Application name:
MyAmazonIAPTestApp
• Company domain:
com.test.myapp
• Package name
(should be created automatically):
myapp.test.com.myamazoniaptestapp
8
Select API 21 (Lollipop) as minimum
SDK. Amazon devices are running on API
21 (Android 5.0 Lollipop)
9
Create a new Empty Activity called
MainActivity. This will create the Java
class,
MainActivity
activity_main.xml
10
Click Finish and let Gradle compile the
project (might take a few minutes).
11
Step 3:
12
Go to your newly created Android
Project folder and find the app/libs
folder (should be MyAmazonIAPTestApp/
app/libs) and paste the in-app-
purchasing-2.0.76.jar so your libs
folder looks like this.
13
In Android Studio, now we need to add
the .jar file to your project dependency
tree. To do this, open build.gradle for
the module app.
14
To add the .jar dependency, under
dependencies change:
implementation fileTree(dir:
‘libs’, include: [‘*.jar’])
to,
15
Step 4:
16
Copy all the text and substitute
This layout contains a button called
it with the following:
subscriptionButton (to subscribe to the
content) that will allow the customer to
<?xml version=”1.0” encoding=”utf-8”?>
<android.support.constraint.ConstraintLayout initiate the request to subscribe to the
xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
content and a TextView called textView
xmlns:tools=”http://schemas.android.com/tools” that will display the status of the
android:layout_width=”match_parent”
android:layout_height=”match_parent”
subscription.
tools:context=”myapp.test.com.myamazoniaptestapp.MainActivity”>
<Button
android:id=”@+id/subscriptionButton”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Buy Subscription”
android:layout_marginTop=”32dp”
app:layout_constraintTop_toTopOf=”parent”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
android:layout_marginStart=”8dp”
android:layout_marginEnd=”8dp” />
<TextView
android:id=”@+id/textView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginEnd=”8dp”
android:layout_marginStart=”8dp”
android:layout_marginTop=”32dp”
android:text=”No Subscription Available.”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toBottomOf=”@+id/subscriptionButton” />
</android.support.constraint.ConstraintLayout>
17
Save and compile. When you launch,
the app should look like this.
18
Step 5:
19
For the sake of this workshop, we’ll use
the JSON provided in the IAP SDK
subscription example.
Amazon-Android-SDKs/
AmazonInAppPurchasing/examples/
SampleIAPSubscriptionsApp
amazon.sdktester.json
20
Paste it in your local device (Fire
Tablet/Android device) storage main
folder.
21
Step 6:
22
The Amazon App Tester lets you test
your implementation without having
to submit the app to the Appstore or
access any cloud-based API.
23
The App Tester automatically detects
that there’s an SDK Tester JSON file
(the previously added amazon.sdktester.
json file) in the local storage of the
device, and that the file contains in-
app items to be used with the in-app
purchasing API.
24
If we click on “5. IAP Items in JSON
File,” we see that the app shows the in-
app items contained in the SDK Tester
JSON.
• A monthly subscription to
“MyMagazine” for $5
• A quarterly subscription to
“MyMagazine” for $5
25
The JSON also carries additional
important information:
26
Our test environment is now fully set.
We now need to implement the In-
App Purchase API in our Android app.
27
Step 7:
PurchasingService
PurchasingListener
Understanding the In-App
Purchase API components
There are multiple components we need
ResponseReceiver to add to our Android app to implement
the In-App Purchasing API and to allow
our user to buy a subscription (or a
Consumable or an Entitlement) from the
Amazon Appstore.
28
These are the main components:
• PurchasingService
PurchasingService Class that initiates requests through
the Amazon Appstore.
• ResponseReceiver
PurchasingListener Class that receives broadcast intents
from the Amazon Appstore.
• PurchasingListener
ResponseReceiver
Interface that receives asynchronous
responses to the requests initiated by
the PurchasingService.
29
Now let’s see how to implement these
components in our app’s main activity.
30
Add the ResponseReceiver to your app
After the <activity> tag, add the
Android manifest
following elements.
<receiver android:name=”com.amazon.device.iap.ResponseReceiver”>
<intent-filter>
<action
android:name=”com.amazon.inapp.purchasing.NOTIFY”
android:permission=”com.amazon.inapp.purchasing.Permission.NOTIFY” />
</intent-filter>
</receiver>
31
Add the ResponseReceiver to your app
So your Android manifest should look
Android manifest
like this.
<?xml version=”1.0” encoding=”utf-8”?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
At this point, our app, through the
package=”myapp.test.com.myamazoniaptestapp”> ResponseReceiver, is instrumented to
<application listen to responses from the Amazon
android:allowBackup=”true” Appstore.
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:roundIcon=”@mipmap/ic_launcher_round” Now, let’s add the components to
android:supportsRtl=”true” make requests to the Appstore and to
android:theme=”@style/AppTheme”>
<activity android:name=”.MainActivity”> handle the responses in our app.
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<receiver android:name=”com.amazon.device.iap.ResponseReceiver”>
<intent-filter>
<action
android:name=”com.amazon.inapp.purchasing.NOTIFY”
android:permission=”com.amazon.inapp.purchasing.Permission.NOTIFY”
/>
</intent-filter>
</receiver>
</application>
</manifest>
32
Querying the Amazon Appstore for the current
The first thing we need to do is to add
status of in-app items in onResume()
the SKU of our subscription. Since we
only have one magazine to manage,
public class MainActivity extends AppCompatActivity {
we add a string containing the parent
String parentSKU = “com.amazon.sample.iap.subscription.mymagazine”;
Handler handler;
SKU in our main activity right after we
create the MainActivity class. We also
add a handler, which will allow us to
update the interface in the main UI.
33
Querying the Amazon Appstore for the current
Now, we need to query the Amazon
status of in-app items in onResume()
Appstore in order to make sure we
have all the information to 1) populate
@Override
protected void onResume() { the interface, and 2) execute the right
super.onResume();
transactions (previous purchases, user
//getUserData() will query the Appstore for the Users information information, SKU availability).
PurchasingService.getUserData();
//getPurchaseUpdates() will query the Appstore for any previous purchase We need to do this operation in the
PurchasingService.getPurchaseUpdates(true); onResume() method of our activity.
//getProductData will validate the SKUs with Amazon Appstore
final Set<String> productSkus = new HashSet<String>();
productSkus.add(parentSKU);
PurchasingService.getProductData(productSkus);
34
Querying the Amazon Appstore for the current
These methods from the
status of in-app items in onResume()
PurchasingService
@Override
protected void onResume() {
super.onResume(); will query the Amazon Appstore for all
the necessary information.
//getUserData() will query the Appstore for the Users information
PurchasingService.getUserData();
Now, we need to react when the
//getPurchaseUpdates() will query the Appstore for any previous purchase
PurchasingService.getPurchaseUpdates(true);
Amazon Appstore replies with this
information. Our activity needs a
//getProductData will validate the SKUs with Amazon Appstore
final Set<String> productSkus = new HashSet<String>();
productSkus.add(parentSKU); PurchasingListener.
PurchasingService.getProductData(productSkus);
35
Implementing the
Let’s add a PurchasingListener to
PurchasingListener
our activity.
PurchasingListener purchasingListener = new PurchasingListener() {
The PurchasingListener has four
@Override main callback methods that we must
public void onUserDataResponse(UserDataResponse userDataResponse) {
implement:
}
1. onUserDataResponse: Invoked after
@Override
a call to getUserData(). Determines the
public void onProductDataResponse(ProductDataResponse productDataResponse) {
UserId and marketplace of the currently
} logged on user.
@Override
public void onPurchaseResponse(PurchaseResponse purchaseResponse) { 2. onPurchaseUpdatesResponse:
Invoked after a call to
} getPurchaseUpdates (boolean
@Override reset). Retrieves the purchase
public void onPurchaseUpdatesResponse(PurchaseUpdatesResponse purchaseUpdatesRe- history. Amazon recommends
sponse) { that you persist the returned
} PurchaseUpdatesResponse data
}; and query the system only for updates.
36
Implementing the
Let’s add a PurchasingListener to
PurchasingListener
our activity.
PurchasingListener purchasingListener = new PurchasingListener() {
The PurchasingListener has four
@Override main callback methods that we must
public void onUserDataResponse(UserDataResponse userDataResponse) {
implement:
}
@Override 3. onProductDataResponse
public void onProductDataResponse(ProductDataResponse productDataResponse) { (ProductDataResponse
productDataResponse):
}
Invoked after a call to
@Override getProductDataRequest (java.
public void onPurchaseResponse(PurchaseResponse purchaseResponse) {
util.Set skus). Retrieves information
} about SKUs you would like to sell
from your app. Use the valid SKUs in
@Override
public void onPurchaseUpdatesResponse(PurchaseUpdatesResponse purchaseUpdatesRe-
onPurchaseResponse().
sponse) {
4. onPurchaseUpdatesResponse:
} Invoked after a call to purchase (String
};
sku). Used to determine the status of a
purchase.
37
User data response
The first callback we implement
is onUserdataResponse().
Let’s define two variables outside
//Define UserId and MarketPlace
private String currentUserId; of the PurchasingListener
private String currentMarketplace;
that we’ll call currentUserID and
currentMarketplace.
38
User data response
Now let’s override
onUserDataResponse.
@Override
public void onUserDataResponse(UserDataResponse response) {
This method recovers the user ID and
the reference marketplace of the user. In
final UserDataResponse.RequestStatus status = response.getRequestStatus();
case we can’t retrieve this information,
switch (status) { or the callback can’t be executed, our
case SUCCESSFUL:
currentUserId = response.getUserData().getUserId(); code should handle those conditions
currentMarketplace = response.getUserData().getMarketplace(); and fail gracefully (we won’t cover the
break;
implementation details in this workshop,
case FAILED: however).
case NOT_SUPPORTED:
// Fail gracefully.
break;
}
}
39
Product data response
onProductDataResponse allows us to
get information and details about all IAP
items in the catalog and all unavailable
@Override
public void onProductDataResponse(ProductDataResponse productDataResponse) { SKUs. This comes in handy if we want to
switch (productDataResponse.getRequestStatus()) {
case SUCCESSFUL:
strike through specific IAP Items in our
app UI.
//get informations for all IAP Items (parent SKUs)
final Map<String,Product> products = productDataResponse.getProductData();
for ( String key : products.keySet()) {
Product product = products.get(key);
Log.v(“Product:”, String.format( “Product: %s\n Type: %s\n SKU: %s\n
Price: %s\n Description: %s\n” , product.getTitle(), product.getProductType(),
product.getSku(), product.getPrice(), product.getDescription()));
}
break;
case FAILED:
Log.v(“FAILED”, “FAILED” );
break ;
}
}
40
Making a purchase
The first thing we have to do is to
register the PurchasingListener. Let’s
do this in our MainActivity onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) { method.
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PurchasingService.registerListener(this, purchasingListener);
41
Making a purchase
In order to allow the user to make
a purchase, we need to add a
ClickListener to our Button.
Button button = (Button) findViewById(R.id.subscriptionButton);
button.setOnClickListener(new View.OnClickListener() {
@Override The PurchasingService.purchase()
public void onClick(View view) {
PurchasingService.purchase(parentSKU); method will initialize the purchase for a
specific SKU (in this case, our parentSKU
}
}); for the magazine).
42
Making a purchase
Then, we need to add a component to
show on-screen if we are effectively
subscribed to the magazine. Let’s add
//create a handler for the UI changes
handler = new Handler(Looper.getMainLooper()){ this in our onCreate().
@Override
public void handleMessage(Message msg) {
if (msg.obj.equals(“Subscribed”)){ The handler will wait for the message
TextView textView = (TextView) findViewById(R.id.textView); “subscribed,” which will indicate that we
textView.setText(“SUBSCRIBED”);
textView.setTextColor(Color.RED); should update the TextView color and
text to show that we’re subscribed to
}
} the content.
};
43
Making a purchase
Now, we need to handle the
onPurchaseResponse() callback
in our PurchaseListener.
@Override
public void onPurchaseResponse(PurchaseResponse purchaseResponse) { onPurchaseResponse() is triggered
switch (purchaseResponse.getRequestStatus()) {
only when the user makes a specific
case SUCCESSFUL: purchase for the first time.
PurchasingService.notifyFulfillment(purchaseResponse.getReceipt().getReceiptId(),
FulfillmentResult.FULFILLED); If the purchase is successful, then we
break ; can fulfill the item to the customer
case FAILED: using PurchasingService.
notifyFulfillment().
break ;
} This would trigger the
onPurchaseUpdateResponse()
} callback, and that’s the last component
that we need to implement.
44
Fulfilling the item to the user
In order to fulfill the item to
the user, we need to do it in the
onPurchaseUpdateResponse().
@Override
public void onPurchaseUpdatesResponse(PurchaseUpdatesResponse response) { That’s because we would fulfill the
subscription any time the user logs in, if
// Process receipts the receipt is still valid.
switch (response.getRequestStatus()) {
case SUCCESSFUL:
for ( final Receipt receipt : response.getReceipts()) { If the status of the Request is
// Process receipts successful, it means this user has the
if (!receipt.isCanceled()){
Message m= new Message(); right to access the item (in this case, the
m.obj=”Subscribed”; subscription).
handler.handleMessage(m);
45
Step 8:
46
If we click on the dropdown menu,
we can select from the multiple
subscription periods we defined in the
amazon.sdktester.json file. In this case,
we have a $5 monthly subscription and
a $12 quarterly subscription.
47
If we complete a purchase, you’ll see
that the TextView will change color
and text to show we are subscribed to
the magazine.
48
Now, if we exit our app and open the
Amazon App Tester, click on “In-App
Purchasing API” and “4. Manage
Transactions,” we can see the
transaction details.
49
Next Steps Test your app using Amazon
Live App Testing
Once you finish adding
App testers experience the app and
IAP to your Android app have access to the full suite of Amazon
and complete testing, the services—including In-App Purchasing—
in the actual production environment, so
next step would be to
you can ensure that your app is working
publish your app on the as expected.
Amazon Appstore and start
App testers are not charged for
monetizing. downloading your test app, and are
not charged for in-app items. This tool
allows you to improve quality, increase
However, before launching
stability, and optimize the experience
the app in production, before you push your app live for all
there are a few additional customers to download.
steps you might want to To learn more about Live App Testing,
consider. see here: https://developer.amazon.
com/live-app-testing
50
Next Steps Verify your customer 3. Send the transaction’s userId and
receiptID from your app to your
receipts using Receipt server.
Once you finish adding Verification Service (RVS)
IAP to your Android app 4. Send a request from your server to
The Receipt Verification Service (RVS) RVS to verify the receipt.
and complete testing, the enables validation of purchases made by
next step would be to your app’s users from your own server. 5. Send the result of the RVS
verification back to your app.
publish your app on the This is very useful if you need to query
Amazon Appstore and start Amazon about the current status of a 6. If the receipt is valid, fulfill the
specific receipt. item. This means granting access
monetizing.
to the in-app item for one-time
The following workflow describes the use (consumable) or continued
However, before launching basic process for verifying purchase use (non-consumable). It may also
transactions: require that you push the content
the app in production,
to the user’s device, such as for a
there are a few additional 1. A user completes an in-app
subscription.
purchase.
steps you might want to
consider. 2. Get the receiptID returned to the
onPurchaseResponse() callback.
51
Next Steps The following diagram 3. To enable access, your app then
sends information from the receipt
illustrates the RVS workflow to your server. Finally, your server
Once you finish adding validates this transaction by
You can also use RVS to enable access
IAP to your Android app to a subscription purchased on another querying RVS.
and complete testing, the platform, like your website, as long To learn more about RVS, see the official
as the purchase was made through
next step would be to complete documentation here:
Amazon. The following scenario https://developer.amazon.com/docs/in-app-
publish your app on the describes this workflow: purchasing/iap-rvs-for-android-apps.html.
Amazon Appstore and start
1. A user purchases a subscription
monetizing. through Amazon via your
company’s website.
However, before launching 2. Your app receives a receipt for the
the app in production, purchased subscription.
there are a few additional
steps you might want to
consider.
52
2. App forwards the
receipt to the server Your server (URL)
to download content
1. API returns a
purchase receipt
4. Receipt verification
service confirms
Buy Now receipt validity 3. Server checks with
Amazon’s Receipt
Verification Service
to ensure validity of
User completes receipt
in-app purchase
Receipt
Verification Service
54
Free content to help intrepid app developers.
To acquire a free digital download of this book, visit the Developer Portal and search the title,
“How to Add Amazon In-App Purchases and Subscriptions to Android Apps.”
www.developer.amazon.com
Copyright 2018 Amazon.com, Inc. and/or affiliates. All rights reserved. Amazon, the Amazon
logo, and the Amazon Appstore are trademarks of Amazon.com, Inc., or its affiliates. Amazon’s
trademarks and trade dress may not be used in connection with any product or service that
is not Amazon’s, in any manner that is likely to cause confusion among customers, or in any
manner that disparages or discredits Amazon. All other trademarks not owned by Amazon are
property of their respective owners, who may or not may not be affiliated with, connected to,
or sponsored by Amazon.
This book or parts thereof may not be reproduced in any form, stored in any retrieval system,
or transmitted in any form or by any means – electronic, mechanical, photocopy, recording or
otherwise – without prior written permission of the publisher – except as provided by the Unit-
ed States of America copyright law.
The content of this book and the website links contained herein are simply for educational
purposes, and are not intended to replace professional business advice or guarantee business
outcomes. Every effort has been made to ensure that the content provided in this content is
accurate and helpful for our readers at the time of publishing. However, this is not an exhaus-
tive treatment of the subjects. No liability is assumed for losses or damages to the information
provided. You are responsible for your own choices, actions, and results.
First edition
March 2018
55