{"id":27151411,"url":"https://github.com/checkout/frames-android","last_synced_at":"2025-07-27T08:35:02.341Z","repository":{"id":32794866,"uuid":"140300675","full_name":"checkout/frames-android","owner":"checkout","description":"Frames Android: making native card payments simple","archived":false,"fork":false,"pushed_at":"2025-07-14T10:52:04.000Z","size":14693,"stargazers_count":3,"open_issues_count":14,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-14T13:57:40.545Z","etag":null,"topics":["android","card-validations","checkout","credit-card","fintech","mobile-payments","payment","payment-express","tokenisation","validation"],"latest_commit_sha":null,"homepage":"https://www.checkout.com/docs/integrate/sdks/android-sdk","language":"Kotlin","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/checkout.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-07-09T14:52:40.000Z","updated_at":"2025-07-14T10:52:07.000Z","dependencies_parsed_at":"2023-10-02T22:02:17.312Z","dependency_job_id":"6819eaa0-fc62-454d-8648-6fabf4b61d83","html_url":"https://github.com/checkout/frames-android","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/checkout/frames-android","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fframes-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fframes-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fframes-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fframes-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/checkout","download_url":"https://codeload.github.com/checkout/frames-android/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/checkout%2Fframes-android/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267329910,"owners_count":24069943,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","card-validations","checkout","credit-card","fintech","mobile-payments","payment","payment-express","tokenisation","validation"],"created_at":"2025-04-08T14:40:24.441Z","updated_at":"2025-07-27T08:35:02.322Z","avatar_url":"https://github.com/checkout.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Frames Android SDK\n[![CircleCI](https://circleci.com/gh/checkout/frames-android/tree/master.svg?style=svg)](https://circleci.com/gh/checkout/frames-android/tree/master)\n[![](https://jitpack.io/v/checkout/frames-android.svg)](https://jitpack.io/#checkout/frames-android)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nStart accepting online payments in just a few minutes with our Android SDK. It's quick and easy to integrate, accepts online payments from all major debit and credit cards, and is customizable to your brand.\n\n\n\u003cdiv align=\"center\"\u003e\n    \u003cimg width=40% src=\"readme-docs/frames-android-demo.gif\"\u003e\n\u003c/div\u003e\n\n\n\n\n## Requirements\n- Android minimum SDK 21\n\n\u003e Compatibility verified with `targetSdk` versions 21 to 34\n\n\n\n## Documentation\n\nFrames for Android tokenises consumer data for use within [Checkout.com](https://www.checkout.com)'s payment infrastructure. We want to abstract all the complexity in taking payments and building a payment screen from your Mobile Application and allow you to focus on your core business.\n\n- [Integration](#Integration): _a guide for consuming our SDK in your Android app_\n\n- [Demo projects](#Demo-projects): _We've created projects showcasing the range of functionality available in our SDKs while testing each distribution method offered_\n\n- [Get started](#Get-started): _Start testing what you can achieve by presenting inside your Applications UI_\n\n- [Make it your own](#Make-it-your-own): _Customising the UI to become a part of your app_\n\n- [Other features](#Other-features): _How we help with Google Pay \u0026 3D Secure Challenges_\n\n- [Make a hosted CVV payment](#Make-a-payment-with-a-hosted-CVV): _Make a compliant saved card payment with hosted CVV tokenisation_\n\n- [Migrating](#Migrating): _If you have used 3.x.x version before_\n\n- [License](#License)\n\n\nComplete information will be found in the [Checkout Docs](https://www.checkout.com/docs/integrate/sdks/android-sdk).\n\nYou can find the Frames API reference [on our KDoc](https://checkout.github.io/frames-android/index.html).\n\n\n\n## Integration\n\nAdd JitPack repository to the project level `build.gradle` file:\n```groovy\n// project gradle file\nallprojects {\n    repositories {\n        maven { url 'https://jitpack.io' }\n        maven { url 'https://maven.fpregistry.io/releases' }\n    }\n}\n```\n\nAdd Frames SDK dependency to the module gradle file:\n```groovy\n// module gradle file\ndependencies {\n    implementation 'com.github.checkout:frames-android:\u003clatest_version\u003e'\n}\n```\n\n\n\u003e You can find more about the installation and available versions on [![](https://jitpack.io/v/checkout/frames-android.svg)](https://jitpack.io/#checkout/frames-android)\n\n\u003e Please keep in mind that the Jitpack repository should to be added to the project gradle file while the dependency should be added in the module gradle file. (More about build configuration files is available [here](https://developer.android.com/studio/build))\n\n\n## Demo projects\nWe've worked with Product and Design to create simple demo applications that showcase our SDKs, that you'll be able to run locally as soon as you clone the repository.\n\nYou will find our demo apps in the root of the repository, inside respective folders:\n- `app` - Java and Imperative UI. Covers default style and 3DS.\n- `example_app_frames` - Kotlin and Declarative UI. Covers: default and custom style, theming, 3DS and Google Pay.\n\nOnce running `example_app_frames`, you will find the home screen with a number of design options. We have tried to make them pretty contrasting to give your UI/UX teammates an idea of what can be achieved. We've also tried to write the code in the simplest way to track and understand how each UI flavour was created. Just start from `HomeScreen.kt` and follow the button actions in code for some examples on how we achieve those UIs.\n\n\n## Get started\nIf you got here, we'll either assume you've completed Integration or you're just curious. If none, then please complete [Integration](#Integration) first.\n\n### Step 1: Create a callback for the Payment flow\n```kotlin\nval paymentFlowHandler = object : PaymentFlowHandler {\n    override fun onSubmit() {\n        // form submit initiated; you can potentially display a loader\n    }\n    override fun onSuccess(tokenDetails: TokenDetails) {\n        // your token is here\n    }\n    override fun onFailure(errorMessage: String) {\n        // token request error\n    }\n    override fun onBackPressed() {\n        // the user decided to leave the payment page\n    }\n}\n```\n\n### Step 2: Prepare your object responsible for the Frames configuration\n```kotlin\n/*\n  Providing PrefillData is optional. However, using this can increase the speed of the checkout experience for your users by pre-filling non-sensitive information.\n */\nval userPrefillData = PrefillData(\n    cardHolderName = \"Test Name\",        // represent the cardHolderName in PaymentDetail form\n    billingFormAddress = BillingFormAddress(\n        name = \"UserName\",               // represent the cardHolderName in Billing form\n        address = Address(\n            addressLine1 = \"Hill road\",\n            addressLine2 = \"90 Tottenham Court Road\",\n            city = \"London\",\n            state = \"England\",\n            zip = \"W1T 4PY\",\n            country = Country.from(iso3166Alpha2 = \"GB\")\n        ),\n        phone = Phone(\"7405987323\", Country.UNITED_KINGDOM)\n    )\n)\n\n// Create a configuration object for your Payment form\nval paymentFormConfig = PaymentFormConfig(\n    publicKey = PUBLIC_KEY,                     // set your public key\n    context = context,                          // set context\n    environment = Environment.SANDBOX,          // set the environment\n    paymentFlowHandler = paymentFlowHandler,    // set the callback\n    style = PaymentFormStyle(),                 // set the style\n    supportedCardSchemeList = emptyList(),      // set supported card schemes, by default uses all schemes\n    prefillData = userPrefillData               // set prefill data for user to improve their checkout experience\n)\n```\n\n#### A note on `cardHolderName` and `name` in `PrefillData`\nPlease note that `cardHolderName` in the payment form and `name` in the billing form represent the same info, so you should only include this either in the payment or billing form, not both. If you do include it in both places, we will prioritise passing cardholderName in the Tokenisation request.\n\nAdditionally, if you hide these fields on the actual payment and billing forms, but include them in the `PrefillData` object, we will still pass them in the Tokenisation request. You may want to do this if you want to include this information in the Tokenisation request, but do not want the user to fill it out on the UI.\n\n### Step 3: Create a Payment mediator\n```kotlin\nval paymentFormMediator = PaymentFormMediator(paymentFormConfig)\n```\n\n### Step 4: Use a Payment form mediator to get and show Payment form\n\n#### With Compose UI\n```kotlin\npaymentFormMediator.PaymentForm()               // Compose function\n```\n\n#### With Activity\n```kotlin\noverride fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    paymentFormMediator.setActivityContent(this)\n}\n```\n\n#### With Fragment\n```kotlin\noverride fun onCreateView(\n    inflater: LayoutInflater,\n    container: ViewGroup?,\n    savedInstanceState: Bundle?\n): View = paymentFormMediator.provideFragmentContent(this)\n```\n\n## Make it your own\n\u003csub\u003e!!! Any customisation needs to be done before creating Payment form mediator. Once mediator is created, any changes done on style will not be reflected in the UI !!!\u003c/sub\u003e\n\nWe have been working hard to provide a selection of ways to make it your own. In order of complexity we'll start with:\n\n### Modify Default\nIn our [Get started](#Get-started) example we have used Default Style to get something working quickly. If that was mostly what you were looking for, then modify individual properties should be the best option for you.\n\n```kotlin\nval paymentFormStyle = PaymentFormStyle()\nval customInputComponentStyle = DefaultLightStyle.inputComponentStyle(\n    titleTextId = R.string.custom_card_number_title,\n    withLeadingIcon = true,\n    margin = Margin(bottom = 16)\n)\npaymentFormStyle.paymentDetailsStyle.cardNumberStyle.inputStyle = customInputComponentStyle\n```\n\nTo disable `cardHolderName` and `BillingFormAddress` in the Payment Form, pass a null value to each respective style property in `PaymentDetailsStyle`\n\n```kotlin\nval paymentFormStyle = PaymentFormStyle(\n    paymentDetailsStyle =  PaymentDetailsStyle(\n        addressSummaryStyle = null,\n        cardHolderNameStyle = null\n    )\n)\n```\n\n### Use Theme\nDetailed implementation of this approach can be found in `CustomPaymentFormTheme.kt`. With the Theme, we are aiming to give you a design system that you can use to create the full UI style by providing a small number of properties that we will share across to sub components. Since you might not fully agree with our mapping, you can still individually change each component afterwards (as in the Modify Default example).\n\n```kotlin\nval theme = PaymentFormTheme(\n    paymentFormThemeColors = paymentFormThemeColors,\n    /**\n     * option 1: Use combination of default and custom components\n     */\n    paymentFormComponents = DefaultPaymentFormTheme.providePaymentFormComponents(\n        cardNumber = cardNumber,\n        addressLineOne = addressLineOne,\n        addressLineTwo = addressLineTwo,\n        addBillingSummaryButton = addBillingSummaryButton,\n        editBillingSummaryButton = editBillingSummaryButton\n    ),\n    /**\n     * option 2: Use default components\n     * paymentFormComponents = DefaultPaymentFormTheme.provideComponents()\n     */\n    paymentFormShape = PaymentFormShape(\n        inputFieldShape = Shape.RoundCorner,\n        addressSummaryShape = Shape.Rectangle, buttonShape = Shape.Circle\n    ),\n    paymentFormCornerRadius = PaymentFormCornerRadius(\n        inputFieldCornerRadius = CornerRadius(INPUT_FIELD_CORNER_RADIUS),\n        addressSummaryCornerRadius = CornerRadius(INPUT_FIELD_CORNER_RADIUS)\n    )\n)\nval style = PaymentFormStyleProvider.provide(theme)\n```\nWe think this approach should hit a good balance between great control of UI \u0026 simple, concise code. However if you still find the mapping to need excessive customisation, our final approach may be more to your liking.\n\n### Declare all components\nThis is by no means the easy way, but it is absolutely the way to fully customise every property, and discover the full extent of customisability as you navigate through `CustomPaymentDetailsStyle.kt`.\n\n```kotlin\nval paymentDetailsStyle: PaymentDetailsStyle = PaymentDetailsStyle(\n    paymentDetailsHeaderStyle = ScreenHeaderStyle(..),\n    cardSchemeStyle = CardSchemeComponentStyle(..),\n    cardNumberStyle = CardNumberComponentStyle(..),\n    expiryDateStyle = ExpiryDateComponentStyle(..),\n    cvvStyle = CvvComponentStyle(..),\n    addressSummaryStyle = AddressSummaryComponentStyle(..),\n    payButtonStyle = PayButtonComponentStyle(..),\n    fieldsContainerStyle = ContainerStyle(..)\n)\nval billingFormStyle: BillingFormStyle = BillingFormStyle(..)\nval paymentFormStyle = PaymentFormStyle(paymentDetailsStyle, billingFormStyle)\n```\nTo use some of our default component styles during custom style creation please take a look on: `DefaultTextStyle.kt`, `DefaultButtonStyle.kt`, `DefaultImageStyle.kt`,`DefaultTextLabelStyle.kt`,`DefaultTextStyle.kt`,`DefaultLightStyle.kt`,`...`.\n\n## Other features\n\n### Handle 3D Secure\nWhen you send a 3D secure charge request from your server you will get back a 3D Secure URL. This is available from `_links.redirect.href` within the JSON response. You can then pass the 3D Secure URL to a `PaymentFormMediator` in order to handle the verification.\n\nThe redirection URLs (`success_url` and `failure_url`) are set in the Checkout.com Hub, but they can be overwritten in the charge request sent from your server. It is important to provide the correct URLs to ensure a successful payment flow.\nExample of 3DS handling can be found in demo `app`, `DemoActivity.java`.\n\n#### Step 1: Create 3DS result handler\n```kotlin\nval threeDSResultHandler: ThreeDSResultHandler = { threeDSResult: ThreeDSResult -\u003e\n    when (threeDSResult) {\n        // Used when [ProcessThreeDSRequest.redirectUrl] contains [ThreeDSRequest.successUrl]\n        is ThreeDSResult.Success -\u003e { \n            /* Handle success result */\n            threeDSResult.token\n        }\n        // Used when [ProcessThreeDSRequest.redirectUrl] contains [ThreeDSRequest.successUrl]\n        is ThreeDSResult.Failure -\u003e { /* Handle failure result */ }\n        // Used when [ProcessThreeDSRequest.redirectUrl] can't be parsed or when error received from 3DS WebView\n        is ThreeDSResult.Error -\u003e { \n            /* Handle success result */\n            threeDSResult.error\n        }\n    }\n}\n```\n\n#### Step 2: Handle 3DS\n```kotlin\nval request = ThreeDSRequest(\n    container = findViewById(android.R.id.content), // Provide a ViewGroup container for 3DS WebView\n    challengeUrl = redirectUrl,                     // Provide a 3D Secure URL\n    successUrl = \"http://example.com/success\",\n    failureUrl = \"http://example.com/failure\",\n    resultHandler = threeDSResultHandler\n)\npaymentFormMediator.handleThreeDS(request)\n```\n\n### Handle GooglePay\nHandle a Google Pay token payload and retrieve a token, that can be used to create a charge from your backend.\n\n#### Step 1: Create CheckoutApiService\n```kotlin\nval checkoutApiClient = CheckoutApiServiceFactory.create(\n    publicKey = PUBLIC_KEY,                     // set your public key\n    environment = Environment.SANDBOX,          // set context\n    context = context                           // set the environment\n)\n```\n\n#### Step 2: Create a token for GooglePay\n```kotlin\nval request = GooglePayTokenRequest(\n    tokenJsonPayload = tokenJsonPayload,\n    onSuccess = { tokenDetails -\u003e\n       /* Handle success result */\n        tokenDetails.token\n    },\n    onFailure = { errorMessage -\u003e\n        /* Handle failure result */\n    }\n)\ncheckoutApiClient.createToken(request)\n```\n\n## Make a payment with a hosted CVV \nUse our CVV component to make a compliant saved card payment in regions where sending a CVV is always mandatory. \n\nWithin this flow, we will securely tokenise the CVV and return a CVV token to your application layer, which you can then use to continue the payment flow with.\n\n### Step 1: Create the CVVComponentApi\n\n```kotlin\n// Create one time cvvComponentApi\nval cvvComponentApi = CVVComponentApiFactory.create(\n    publicKey = \"PUBLIC_KEY\",                     // set your public key\n    environment = Environment.SANDBOX,           // set the environment\n    context = context                           // set context\n)\n```\n\n### Step 2: Create the CVVComponentMediator using CVVComponentConfig\n\nPrepare the object responsible for the CVV component configuration. \n\nHere you should inject the card scheme in order for the SDK to validate the length of the CVV using `isEnteredCVVValid`. If you don't pass a scheme, we will treat it as `UNKNOWN`. Within `CVVComponentConfig`, you can also configure the `cvvComponentStyle`, which has all the styling attributes of our existing UIs. \n\nIf the CVV is length 0, the SDK will throw a validation error when calling `createToken`.\n\n```kotlin\nval cvvComponentConfig = CVVComponentConfig(\n    cardScheme = CardScheme.fromString(cardSchemeValue = \"your card scheme\"),         // set your card scheme (optional)\n    onCVVValueChange = { isEnteredCVVValid -\u003e                                         // update your listener from the onCVVValueChange \n        enteredVisaCVVUpdated.value = isEnteredCVVValid\n    },\n    cvvInputFieldStyle = inputFieldStyle,                                            // set your cvvInputFieldStyle\n)\n```\n\nOnce you've prepared the CVV component's config, then use the CVVComponentMediator.\n```kotlin\nval cvvComponentMediator = cvvComponentApi.createComponentMediator(cvvComponentConfig)\n```\n\n### Step 3: Load the CVV component\n\nFor Compose based UIs:\n\n```kotlin\ncvvComponentMediator.CVVComponent()\n```\n\nFor XML-based UIs:\n\n```kotlin\n// Access the LinearLayout by its Resource ID\nval linearLayout = findViewById\u003cLinearLayout\u003e(R.id.linearLayout)\n// Get the cvvComponentView \nval cvvComponentView = cvvComponentMediator.provideCvvComponentContent(linearLayout)\n// Add the cvvComponentView into parent Layout\nlinearLayout.addView(cvvComponentView)\n```\n\n#### Step 4: Create a CVV token\n```kotlin\n cvvComponentMediator.createToken { result -\u003e\n    when (result) {\n        is CVVTokenizationResultHandler.Success -\u003e {\n            /* Handle success result */ result.tokenDetails\n        }\n        is CVVTokenizationResultHandler.Failure -\u003e {\n            /* Handle failure result */ result.errorMessage\n        } \n    }\n}\n```\n\nYou can then continue the payment flow with this `token` by passing into a field name as `cvv` in the payment request. \n\n## Migrating\n3DS and GooglePay processing remain unaffected so using them should still work the same.\n\nIf you're using Frames Android from versions prior to v4 (we would strongly recommend using the latest release), this update will bring breaking changes that'll require a little development time.\n\nBecause of our efforts to greatly improve the UI of the Frames and enabling you to customise it to such extents, the approach required is very different. This will require you to:\n- remove usage of Frames older version from your code base. This may be an opportunity to remove a screen as well, or a few other objects that were created only to support older Frames integration!\n- [Get started](#Get-started)\n\n\nWe would like to point out the great benefits that we think v4+ brings to our SDK, like:\n\n- customisable UI focussed on enabling your users to seamlessly transition through the payment flow\n- updated and improved validation logic, in line with our supported card payment methods\n- using our updated UIs provides added security benefits to your customers\n\n## License\n\nFrames Android is released under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheckout%2Fframes-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcheckout%2Fframes-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheckout%2Fframes-android/lists"}