Affirm Android SDK allows you to offer Affirm in your own app.
Download via Gradle:
implementation "com.affirm:affirm-android-sdk:2.0.20"
or Maven:
<dependency>
<groupId>com.affirm</groupId>
<artifactId>affirm-android-sdk</artifactId>
<version>2.0.20</version>
</dependency>
Snapshots of the development version are available in Sonatype's snapshots
repository.
Before you can start the initialization of Affirm SDK, you must first set the AffirmSDK with your public API key
from your sandbox Merchant Dashboard. You must set this key as follows:
Affirm.initialize(new Affirm.Configuration.Builder("public key")
.setEnvironment(Affirm.Environment.SANDBOX)
.setName("merchant name")
.setReceiveReasonCodes("true")
.setLogLevel(Affirm.LOG_LEVEL_DEBUG)
.setCheckoutRequestCode(8001)
.setVcnCheckoutRequestCode(8002)
.setPrequalRequestCode(8003)
.setLocation(Affirm.Location.US) // "CA" for Canadian, "US" for American (If not set, default use US)
.build())
environment
can be set toAffirm.Environment.SANDBOX
for test.- To prevent conflicts, you can set a custom affirm's request code.
You can also set public key
and merchant name
after the initialize
method
Affirm.setMerchantName("merchant name")
Affirm.setPublicKey("public key")
Affirm.setPublicKeyAndMerchantName("public key", "merchant name")
Checkout creation is the process in which a customer uses Affirm to pay for a purchase in your app. You can create a checkout object and launch the affirm checkout using the Checkout function
final Checkout checkout = Checkout.builder()
.setOrderId("order id")
.setItems(items)
.setBilling(shipping)
.setShipping(shipping)
.setShippingAmount(BigDecimal.valueOf(0.0))
.setTaxAmount(BigDecimal.valueOf(100.0))
.setTotal(BigDecimal.valueOf(1100.0))
.setMetadata(metadata)
.build();
Affirm.startCheckout(this, checkout, false);
//It is recommended that you round the total in the checkout request to two decimal places. Affirm SDK converts the float total to integer cents before initiating the checkout, so may round up or down depending on the decimal places. Ensure that the rounding in your app uses the same calculation across your other backend systems, otherwise, it may cause an error of 1 cent or more in the total validation on your end.
-
checkout
object contains details about the order -
useVCN
(boolean) determines whether the checkout flow should use virtual card network to handle the checkout- if
true
, it will returncard info
fromVcnCheckoutCallbacks
. Be sure to override onActivityResult, then call thehandleVcnCheckoutData
method. Please check out the example project for more information.
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (Affirm.handleVcnCheckoutData(this, requestCode, resultCode, data)) { return; } super.onActivityResult(requestCode, resultCode, data); }
@Override public void onAffirmVcnCheckoutCancelled() { Toast.makeText(this, "Vcn Checkout Cancelled", Toast.LENGTH_LONG).show(); } @Override public void onAffirmVcnCheckoutError(@Nullable String message) { Toast.makeText(this, "Vcn Checkout Error: " + message, Toast.LENGTH_LONG).show(); } @Override public void onAffirmVcnCheckoutSuccess(@NonNull CardDetails cardDetails) { Toast.makeText(this, "Vcn Checkout Card: " + cardDetails.toString(), Toast.LENGTH_LONG).show(); }
- if
false
, it will return checkouttoken
fromCheckoutCallbacks
. Be sure to override onActivityResult, then call thehandleCheckoutData
method. Please refer to the example project for more information.
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (Affirm.handleCheckoutData(this, requestCode, resultCode, data)) { return; } super.onActivityResult(requestCode, resultCode, data); }
@Override public void onAffirmCheckoutSuccess(@NonNull String token) { Toast.makeText(this, "Checkout token: " + token, Toast.LENGTH_LONG).show(); } @Override public void onAffirmCheckoutCancelled() { Toast.makeText(this, "Checkout Cancelled", Toast.LENGTH_LONG).show(); } @Override public void onAffirmCheckoutError(String message) { Toast.makeText(this, "Checkout Error: " + message, Toast.LENGTH_LONG).show(); }
- if
Once the checkout has been successfully confirmed by the user, the AffirmCheckoutDelegate object will receive a checkout token. This token should be forwarded to your server, which should then use the token to authorize a charge on the user's account. For more details about the server integration, see our API documentation.
Note - For VCN Checkout, all actions should be done using your existing payment gateway and debit card processor using the virtual card number returned after a successful checkout.
Affirm promotional messaging components—payment messaging and educational modals—show customers how they can use Affirm to finance their purchases. Promos consist of promotional messaging, which appears directly in your app, and a modal, which which offers users an ability to prequalify.
To display promotional messaging, SDK provides a AffirmPromotionButton
class. AffirmPromotionButton
is implemented as follows:
<com.affirm.android.AffirmPromotionButton
android:id="@+id/promo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/price"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
app:htmlStyling="false"
app:affirmTextFont="@font/apercu_bold"
app:affirmTextColor="@android:color/darker_gray"
app:affirmTextSize="16sp"
app:affirmColor="AffirmColorTypeBlue"
app:affirmLogoType="AffirmDisplayTypeLogo"/>
or
// Option1 - Load via findViewById
AffirmPromotionButton affirmPromotionButton1 = findViewById(R.id.promo);
Affirm.configureWithAmount(affirmPromotionButton1, null, PromoPageType.PRODUCT, BigDecimal.valueOf(1100.0), true);
or
// Option2 - Initialize by new
AffirmPromotionButton affirmPromotionButton2 = new AffirmPromotionButton(this);
((FrameLayout)findViewById(R.id.promo_container)).addView(affirmPromotionButton2);
Affirm.configureWithAmount(affirmPromotionButton2, null, PromoPageType.PRODUCT, BigDecimal.valueOf(1100.0), true);
Configure the style of the AffirmPromotionButton
configWithLocalStyling
that will use the local styles.
// You can custom with the AffirmColor, AffirmLogoType, Typeface, TextSize, TextColor
affirmPromotionButton2.configWithLocalStyling(
AffirmColor.AFFIRM_COLOR_TYPE_BLUE,
AffirmLogoType.AFFIRM_DISPLAY_TYPE_LOGO,
ResourcesCompat.getFont(this, R.font.apercu_bold),
android.R.color.darker_gray,
R.dimen.affirm_promotion_size);
configWithHtmlStyling
will use html style from Affirm server.
You can add fonts by following the steps below, so you can customize the fonts in html
-
Add a font file in the /res/font/ directory. Such as lacquer_regular.ttf.
-
Add a declaration for the font file. You can check the detail in typeface
-
Use the font in the css file. You can check the detail in remote_promo.css.
// If you want to custom the style of promo message, should pass the local or remote url and the file of typeface declaration
affirmPromotionButton2.configWithHtmlStyling("file:///android_asset/remote_promo.css", typefaceDeclaration);
Tapping on the AffirmPromotionButton
automatically start prequalification flow.
(Optional) If you want to handle errors, override onActivityResult so that affirm can handle the result.
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (Affirm.handlePrequalData(this, requestCode, resultCode, data)) {
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onAffirmPrequalError(String message) {
Toast.makeText(this, "Prequal Error: " + message, Toast.LENGTH_LONG).show();
}
- You can get promotional message via
fetchPromotion
, aSpannableString
object is returned after the request is successful onPromotionClick
This method handle events that click on the promotional message
TextView promotionTextView = findViewById(R.id.promotionTextView);
Affirm.PromoRequestData requestData = new Affirm.PromoRequestData.Builder(PRICE, true)
.setPageType(null)
.build();
promoRequest = Affirm.fetchPromotion(requestData, promotionTextView.getTextSize(), this, new PromotionCallback() {
@Override
public void onSuccess(@Nullable SpannableString spannableString, boolean showPrequal) {
promotionTextView.setText(spannableString);
promotionTextView.setOnClickListener(v -> Affirm.onPromotionClick(MainActivity.this, requestData, showPrequal));
}
@Override
public void onFailure(@NonNull AffirmException exception) {
Toast.makeText(getBaseContext(), "Failed to get promo message, reason: " + exception.toString(), Toast.LENGTH_SHORT).show();
}
});
- Call
create
method will initiate the request, and callcancel
method to cancel the request.
@Override
protected void onStart() {
super.onStart();
promoRequest.create();
}
@Override
protected void onStop() {
promoRequest.cancel();
super.onStop();
}
The trackOrderConfirmed event triggers when a customer completes their purchase. SDK provides AffirmTrack
object to trigger the tracking.
final AffirmTrack affirmTrack = AffirmTrack.builder()
.setAffirmTrackOrder(affirmTrackOrder)
.setAffirmTrackProducts(affirmTrackProducts)
.build();
Affirm.trackOrderConfirmed(MainActivity.this, trackModel());
We also support using fragment directly, only need to pass a ViewGroup id, we will put the AffirmFragment
in this specified view.
- Checkout
// In your activity/fragment, you need to implement Affirm.CheckoutCallbacks
Affirm.startCheckout(this, R.id.container, checkoutModel(), null, 10, false);
// - Affirm.CheckoutCallbacks
@Override
public void onAffirmCheckoutSuccess(@NonNull String token) {
Toast.makeText(this, "Checkout token: " + token, Toast.LENGTH_LONG).show();
}
@Override
public void onAffirmCheckoutCancelled() {
Toast.makeText(this, "Checkout Cancelled", Toast.LENGTH_LONG).show();
}
@Override
public void onAffirmCheckoutError(@Nullable String message) {
Toast.makeText(this, "Checkout Error: " + message, Toast.LENGTH_LONG).show();
}
- VCN checkout
// In your activity/fragment, you need to implement Affirm.VcnCheckoutCallbacks
Affirm.startCheckout(this, R.id.container, checkoutModel(), null, 10, true);
// - Affirm.VcnCheckoutCallbacks
@Override
public void onAffirmVcnCheckoutCancelled() {
Toast.makeText(this, "Vcn Checkout Cancelled", Toast.LENGTH_LONG).show();
}
@Override
public void onAffirmVcnCheckoutCancelledReason(@NonNull VcnReason vcnReason) {
Toast.makeText(this, "Vcn Checkout Cancelled: " + vcnReason.toString(), Toast.LENGTH_LONG).show();
}
@Override
public void onAffirmVcnCheckoutError(@Nullable String message) {
Toast.makeText(this, "Vcn Checkout Error: " + message, Toast.LENGTH_LONG).show();
}
@Override
public void onAffirmVcnCheckoutSuccess(@NonNull CardDetails cardDetails) {
Toast.makeText(this, "Vcn Checkout Card: " + cardDetails.toString(), Toast.LENGTH_LONG).show();
}
- Promotion
AffirmPromotionButton affirmPromotionButton = findViewById(R.id.promo);
Affirm.configureWithAmount(this, R.id.container, affirmPromotionButton, null, PromoPageType.PRODUCT, PRICE, true, null);
- Site modal
// In your activity/fragment, you need to implement Affirm.PrequalCallbacks
Affirm.showSiteModal(this, R.id.container, null, "5LNMQ33SEUYHLNUC");
@Override
public void onAffirmPrequalError(@Nullable String message) {
Toast.makeText(this, "Prequal Error: " + message, Toast.LENGTH_LONG).show();
}
- Product modal
// In your activity/fragment, you need to implement Affirm.PrequalCallbacks
Affirm.showProductModal(this, R.id.container, PRICE, null, PromoPageType.PRODUCT, null)
@Override
public void onAffirmPrequalError(@Nullable String message) {
Toast.makeText(this, "Prequal Error: " + message, Toast.LENGTH_LONG).show();
}
- Since there is no callback, it will return success after 10 seconds timeout
- We will replace using the HTTP API after the API is done
- Copy the content of the
gradle.properties.template
toaffirm/gradle.properties
. This step is optional. There is a step insideaffirm/build.gradle
to do this automatically. - Run the
samples-java
orsamples-kotlin
within Android Studio.
- If you are using an older version of the SDK, you can refer to this upgrade document. We recommend that you install the latest version to access the most up-to-date features and experience.
- All notable changes to this project will be documented in changelog document.