{"templateId":"markdown","versions":[{"version":"v1","label":"v1","link":"/products/checkout/flutter/native-sdk","default":true,"active":true,"folderId":"27aa35cb"}],"sharedDataIds":{"sidebar":"sidebar-products/checkout/flutter/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["partial","admonition","tabs","tab","code-snippet"]},"custom_product":"Checkout","type":"markdown"},"seo":{"title":"Flutter integration with Native SDKs","description":"Worldpay for Developers - docs, code examples, resources and tools. Everything you need to build your omnichannel payment solution.","siteUrl":"https://docs.worldpay.com/access","image":"/access/assets/worldpay-logo-light.21b7daf79984773a9fcd7d4fbcb07ae5289dfffd6023c4c3dca720c7058e53dc.33f780a6.svg","keywords":"documentation, api, openapi, sdks, developer, payments, json, payouts, 3ds","jsonLd":{"@context":"https://schema.org","@type":"Organization","url":"https://docs.worldpay.com/access","name":"Worldpay"},"meta":[{"name":"google-site-verification","content":"zjziIKaP3ImsqsfhYnEBnq1R85UabiSwl7HTXuwtZuo"},{"name":"doc_product","content":"Access"},{"name":"doc_category","content":"Documentation"}],"llmstxt":{"hide":false,"sections":[{"title":"Payments API","description":"Payment orchestration API combining fraud assessment, 3ds authentication, SCA exemptions, Worldpay Token creation and a card or wallet based payment.","includeFiles":["products/payments/@20240601/**/*"],"excludeFiles":[]},{"title":"Payment Queries API","description":"Querying your payments data, based on a variety of parameters.","includeFiles":["products/payment-queries/@v1/**/*"],"excludeFiles":[]},{"title":"Card BIN Data API","description":"Provides detailed information about a card.","includeFiles":["products/card-bin/@v1/**/*"],"excludeFiles":[]},{"title":"3DS Authentication API","description":"Request 3DS authentication to protect against fraud, be SCA compliant and to shift liability using this standalone API.","includeFiles":["products/3ds/@v3/**/*"],"excludeFiles":[]},{"title":"FraudSight API","description":"Request a risk assessment and receive a response with an outcome (e.g. lowRisk) using this standalone API.","includeFiles":["products/fraudsight/@v1/**/*"],"excludeFiles":[]},{"title":"Checkout SDK","description":"Integrate using our clientside SDKs for both web and native devices. Benefit from SAQ-A/PCI-SSF compliance.","includeFiles":["products/checkout/web/@v2/**/*","products/checkout/ios/@v4/**/*","products/checkout/android/@v4/**/*","products/checkout/react-native/@v3/**/*","products/checkout/flutter/@v1/**/*"],"excludeFiles":[]},{"title":"Tokens API","description":"Minimizes the exposure of sensitive card details and increases the security of your customer's card details.","includeFiles":["products/tokens/@v3/**/*"],"excludeFiles":[]},{"title":"Card Payments API","description":"Request a card payment using this standalone API, requires separate requests for 3DS, Fraud assessment etc.","includeFiles":["products/card-payments/@v7/**/*"],"excludeFiles":[]},{"title":"Card Verifications API","description":"Verify your customer's card to maximize your authentication rates.","includeFiles":["products/card-verifications/@v6/**/*"],"excludeFiles":[]},{"title":"Account Payouts API","description":"Send funds to your customer's bank accounts and search for payouts using parameters.","includeFiles":["products/account-payouts/@20250101/**/*"],"excludeFiles":[]},{"title":"APMs","description":"Pay using eWallets, bank transfers, direct debits, local card schemes, Postpay and eInvoice/ Buy Now Pay Later.","includeFiles":["products/apms/@20240701/**/*"],"excludeFiles":[]},{"title":"Balance API","description":"Request your account details for a single account or all accounts under an entity.","includeFiles":["products/balance/@20250101/**/*"],"excludeFiles":[]},{"title":"Card Payouts API","description":"Send funds to your customer's cards.","includeFiles":["products/card-payouts/@v4/**/*"],"excludeFiles":[]},{"title":"Events (Webhooks)","description":"Receive status updates from Access Worldpay by setting up a webhook.","includeFiles":["products/events/@v1/**/*"],"excludeFiles":[]},{"title":"FX API","description":"Manage Foreign Exchange (FX) on your payments.","includeFiles":["products/fx/@v1/**/*"],"excludeFiles":[]},{"title":"Hosted Payment Pages (HPP) API","description":"Our low-code option to take payments securely at the lowest PCI compliance level - SAQ A.","includeFiles":["products/hosted-payment-pages/@v1/**/*"],"excludeFiles":[]},{"title":"Money Transfers API","description":"Money Transfer OCTs (Original Credit Transaction) allow funds to be pushed to an eligible card in 30 minutes or less.","includeFiles":["products/money-transfers/@v1/**/*"],"excludeFiles":[]},{"title":"Parties API","description":"Create parties, manage your payout instruments and beneficial owners and carry out identity verification checks.","includeFiles":["products/parties/@20250101/**/*"],"excludeFiles":[]},{"title":"SCA Exemptions API","description":"Maximize a frictionless checkout experience by using issuer data insights to apply exemptions.","includeFiles":["products/sca-exemptions/@v1/**/*"],"excludeFiles":[]},{"title":"Split Payments API","description":"Divide funds from a single payment amongst yourself and your parties/sellers.","includeFiles":["products/split-payments/@20250625/**/*"],"excludeFiles":[]},{"title":"Statements API","description":"Retrieve your account statement and see individual entries for all credits and debits.","includeFiles":["products/statements/@20250101/**/*"],"excludeFiles":[]},{"title":"Transfers API","description":"Transfer funds from source account to target account.","includeFiles":["products/transfers/@20250101/**/*"],"excludeFiles":[]},{"title":"Verified Tokens API","description":"Verified Tokens ensures that your customer's payment details are valid and CIT compliant when creating a token.","includeFiles":["products/verified-tokens/@v3/**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Last updated"]},": 17 March 2025"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"flutter-integration-with-native-sdks","__idx":0},"children":["Flutter integration with Native SDKs"]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The integration leverages ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://docs.flutter.dev/platform-integration/platform-channels"},"children":["Flutter platform channels"]}," to configure and render our Native SDKs for ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/checkout/ios"},"children":["iOS"]}," and ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/checkout/android"},"children":["Android"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You create a form containing the Access Checkout UI components in the iOS and Android projects."," ","This form is then rendered on the Flutter application using a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PlatformViewLink"]}," for Android or a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UiKitView"]}," for iOS."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The communication between Native and Flutter is done via method channels."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"get-started","__idx":2},"children":["Get started"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To integrate our Checkout Native iOS and Android SDKs into Flutter you ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["must"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["add our Checkout SDKs to iOS and Android"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["implement platform-specific native views"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["create a method channel for communication between Native and Flutter"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["expose the Native views to Flutter"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["optionally implement validation  and event listeners"]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Full sample integration"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can see an example demo of a Flutter integration with Native iOS and Android SDKs ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/Worldpay/access-checkout-flutter-demo/tree/main/access_checkout_flutter_native_sdk_demo"},"children":["in our ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["access-checkout-flutter-demo"]}," GitHub repository"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"on-the-native-side","__idx":3},"children":["On the Native side"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"add-our-ios-and-android-checkout-sdk","__idx":4},"children":["Add our iOS and Android Checkout SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Firstly, you must add the iOS and Android dependencies manually to the Android and iOS projects within your Flutter application."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"android-add-sdk-dependency","__idx":5},"children":["Android: add SDK dependency"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You must add the Android Checkout SDK to your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["android/app/build.gradle"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To ensure compatibility, the SDK also requires a minimum SDK version of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["26"]},"."," ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"build.gradle.kts (Kotlin)","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/add-dependencies/android-gradle.kts","language":"java","title":"android/app/build.gradle.kts","header":{"title":"android/app/build.gradle.kts","controls":{"copy":{}}},"lang":"java","source":"android {\n    defaultConfig {\n        minSdk = 26\n    }\n}\n\ndependencies {\n    implementation(\"com.worldpay.access:access-checkout-android:4.0.0\")\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"build.gradle (Gradle)","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/add-dependencies/android-gradle.gradle","language":"java","title":"android/app/build.gradle","header":{"title":"android/app/build.gradle","controls":{"copy":{}}},"lang":"java","source":"android {\n    defaultConfig {\n        minSdk 26\n    }\n}\n\ndependencies {\n    implementation 'com.worldpay.access:access-checkout-android:4.0.0'\n}\n"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"ios-add-sdk-dependency","__idx":6},"children":["iOS: add SDK dependency"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You must add the iOS Checkout SDK to your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ios/Podfile"]},"."," ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"Podfile","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/add-dependencies/Podfile","language":"ruby","title":"ios/Podfile","header":{"title":"ios/Podfile","controls":{"copy":{}}},"lang":"ruby","source":"target 'Runner' do\n  pod 'AccessCheckoutSDK'\nend\n\n\n"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"implement-native-views","__idx":7},"children":["Implement native views"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The Access Checkout SDK provides the UI elements, but to integrate them into Flutter you must make use of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PlatformViews"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"android-create-custom-view","__idx":8},"children":["Android: create custom view"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MainActivity.kt"]}," - the entry point responsible for registering the ViewFactory and binding the ViewFactory to"," ","a platform channel."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutView.kt"]}," - renders the Access Checkout UI, handles session generation and validation and communicates to"," ","Flutter via the Method Channel."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutViewFactory.kt"]}," - creates and configures instances of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutView"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["access_checkout_layout.xml"]}," - contains the UI layout of the Access Checkout fields (Pan, Expiry and CVC)."," ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]}]}]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"MainActivity.kt","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/android/MainActivity.kt","language":"kt","title":"android/app/src/main/kotlin/com/example/flutter/MainActivity.kt","header":{"title":"android/app/src/main/kotlin/com/example/flutter/MainActivity.kt","controls":{"copy":{}}},"lang":"kt","source":"package com.example.access_checkout_flutter_native_sdk_demo\n\nimport com.example.access_checkout_flutter_native_sdk_demo.AccessCheckoutViewFactory\nimport io.flutter.embedding.android.FlutterActivity\nimport io.flutter.embedding.engine.FlutterEngine\n\nclass MainActivity : FlutterActivity() {\n    private val METHOD_CHANNEL_NAME = \"com.worldpay.flutter/accesscheckout\"\n\n    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {\n        super.configureFlutterEngine(flutterEngine)\n        val registry = flutterEngine\n            .platformViewsController\n            .registry\n\n        registry\n            .registerViewFactory(\n                \"com.worldpay.flutter/accesscheckout\",\n                AccessCheckoutViewFactory(\n                    flutterEngine.dartExecutor.binaryMessenger,\n                    METHOD_CHANNEL_NAME,\n                    this\n                )\n            )\n    }\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"AccessCheckoutView.kt","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/android/AccessCheckoutView.kt","language":"kt","title":"android/app/src/main/kotlin/com/example/flutter/AccessCheckoutView.kt","header":{"title":"android/app/src/main/kotlin/com/example/flutter/AccessCheckoutView.kt","controls":{"copy":{}}},"lang":"kt","source":"package com.example.access_checkout_flutter_native_sdk_demo\n\nimport android.content.Context\nimport android.graphics.Color\nimport android.graphics.drawable.GradientDrawable\nimport android.view.LayoutInflater\nimport android.view.View\nimport androidx.lifecycle.LifecycleOwner\nimport com.worldpay.access.checkout.client.api.exception.AccessCheckoutException\nimport com.worldpay.access.checkout.client.session.AccessCheckoutClient\nimport com.worldpay.access.checkout.client.session.AccessCheckoutClientBuilder\nimport com.worldpay.access.checkout.client.session.listener.SessionResponseListener\nimport com.worldpay.access.checkout.client.session.model.CardDetails\nimport com.worldpay.access.checkout.client.session.model.SessionType\nimport com.worldpay.access.checkout.client.validation.AccessCheckoutValidationInitialiser\nimport com.worldpay.access.checkout.client.validation.config.CardValidationConfig\nimport com.worldpay.access.checkout.client.validation.listener.AccessCheckoutCardValidationListener\nimport com.worldpay.access.checkout.client.validation.model.CardBrand\nimport com.worldpay.access.checkout.ui.AccessCheckoutEditText\nimport io.flutter.plugin.common.MethodChannel\nimport io.flutter.plugin.platform.PlatformView\n\n\nclass AccessCheckoutView(\n    private val lifecycleOwner: LifecycleOwner,\n    private val methodChannel: MethodChannel,\n    context: Context,\n    creationParams: Map<String, Any>,\n) :\n    PlatformView {\n    private val layout: View\n    private val panInput: AccessCheckoutEditText\n    private val expiryInput: AccessCheckoutEditText\n    private val cvcInput: AccessCheckoutEditText\n\n    private var baseUrl: String = creationParams[\"baseUrl\"] as String\n    private var checkoutId: String = creationParams[\"checkoutId\"] as String\n    private var useCardValidation: Boolean =\n        creationParams[\"useCardValidation\"] as? Boolean ?: false\n\n    private var accessCheckoutClient: AccessCheckoutClient\n\n    init {\n        layout = LayoutInflater.from(context)\n            .inflate(R.layout.access_checkout_layout, null)\n\n        panInput = layout.findViewById(R.id.pan_input)\n        expiryInput = layout.findViewById(R.id.expiry_date_input)\n        cvcInput = layout.findViewById(R.id.cvc_input)\n\n        if (useCardValidation) {\n            initializeCardValidation()\n        }\n        accessCheckoutClient = AccessCheckoutClientBuilder()\n            .baseUrl(baseUrl)\n            .checkoutId(checkoutId)\n            .lifecycleOwner(lifecycleOwner)\n            .sessionResponseListener(\n                object : SessionResponseListener {\n                    override fun onError(error: AccessCheckoutException) {\n                        methodChannel.invokeMethod(\"onSessionError\", \"Could not create session\")\n                    }\n\n                    override fun onSuccess(sessionResponseMap: Map<SessionType, String>) {\n                        // Important: Flutter will not understand SessionType\n                        // therefore it needs to be converted into a JSON-serializable format\n                        val sessionData = sessionResponseMap.mapKeys { it.key.name }\n                        methodChannel.invokeMethod(\"onSessionGenerated\", sessionData)\n                    }\n                }\n            )\n            .context(context)\n            .build()\n\n        methodChannel.setMethodCallHandler { call, result ->\n            when (call.method) {\n                \"generateSession\" -> generateSession()\n                else -> result.notImplemented()\n            }\n        }\n    }\n\n    //    private fun styleComponent() {}\n    private fun initializeCardValidation() {\n        val cardValidationConfig = CardValidationConfig.Builder()\n            .baseUrl(baseUrl)\n            .pan(panInput)\n            .expiryDate(expiryInput)\n            .cvc(cvcInput)\n            .lifecycleOwner(lifecycleOwner)\n            .enablePanFormatting()\n            .validationListener(object : AccessCheckoutCardValidationListener {\n                override fun onBrandChange(cardBrand: CardBrand?) {\n                    // TODO: Update the brand image using your SVG loader\n                }\n\n                override fun onCvcValidated(isValid: Boolean) {\n                    updateUIField(cvcInput, isValid)\n                    if (!isValid) {\n                        methodChannel.invokeMethod(\"onValidationUpdated\", false)\n                    }\n                }\n\n                override fun onExpiryDateValidated(isValid: Boolean) {\n                    updateUIField(expiryInput, isValid)\n                    if (!isValid) {\n                        methodChannel.invokeMethod(\"onValidationUpdated\", false)\n                    }\n                }\n\n                override fun onPanValidated(isValid: Boolean) {\n                    updateUIField(panInput, isValid)\n                    if (!isValid) {\n                        methodChannel.invokeMethod(\"onValidationUpdated\", false)\n                    }\n\n                }\n\n                override fun onValidationSuccess() {\n                    methodChannel.invokeMethod(\"onValidationUpdated\", true)\n                }\n\n            })\n            .build()\n\n        AccessCheckoutValidationInitialiser.initialise(cardValidationConfig)\n    }\n\n    private fun updateUIField(field: AccessCheckoutEditText, isValid: Boolean) {\n        val colour = if (isValid) Color.GREEN else Color.RED\n\n        //Update Text color\n        field.setTextColor(colour)\n        //Update Border\n        val border = GradientDrawable()\n        border.setStroke(3, colour)\n        field.background = border\n    }\n\n\n    private fun generateSession() {\n\n        val cardDetails = CardDetails.Builder()\n            .pan(panInput)\n            .expiryDate(expiryInput)\n            .cvc(cvcInput)\n            .build()\n\n\n        accessCheckoutClient.generateSessions(cardDetails, listOf(SessionType.CARD))\n    }\n\n    override fun getView(): View = layout\n    override fun dispose() {}\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"AccessCheckoutViewFactory.kt","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/android/AccessCheckoutViewFactory.kt","language":"kt","title":"android/app/src/main/kotlin/com/example/flutter/AccessCheckoutViewFactory.kt","header":{"title":"android/app/src/main/kotlin/com/example/flutter/AccessCheckoutViewFactory.kt","controls":{"copy":{}}},"lang":"kt","source":"package com.example.access_checkout_flutter_native_sdk_demo\n\nimport android.content.Context\nimport androidx.lifecycle.LifecycleOwner\nimport com.example.access_checkout_flutter_native_sdk_demo.AccessCheckoutView\nimport io.flutter.plugin.common.BinaryMessenger\nimport io.flutter.plugin.common.MethodChannel\nimport io.flutter.plugin.common.StandardMessageCodec\nimport io.flutter.plugin.platform.PlatformView\nimport io.flutter.plugin.platform.PlatformViewFactory\n\nclass AccessCheckoutViewFactory(\n    private val messenger: BinaryMessenger,\n    private val channel: String,\n    private val lifecycleOwner: LifecycleOwner\n) :\n    PlatformViewFactory(StandardMessageCodec.INSTANCE) {\n\n    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {\n        val methodChannel = MethodChannel(messenger, channel)\n        val creationParams: Map<String, Any> = args as Map<String, Any>\n        return AccessCheckoutView(lifecycleOwner, methodChannel, context, creationParams)\n    }\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"access_checkout_layout.xml","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/android/access_checkout_layout.xml","language":"xml","title":"android/app/src/main/res/layout/access_checkout_layout.xml","header":{"title":"android/app/src/main/res/layout/access_checkout_layout.xml","controls":{"copy":{}}},"lang":"xml","source":"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/access_checkout_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginLeft=\"20dp\"\n    android:layout_marginRight=\"20dp\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:orientation=\"horizontal\">\n\n        <com.worldpay.access.checkout.ui.AccessCheckoutEditText\n            android:id=\"@+id/pan_input\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"8\"\n            android:hint=\"Card number\" />\n\n        <ImageView\n            android:id=\"@+id/brand_logo\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"45dp\"\n            android:layout_marginStart=\"8dp\"\n            android:scaleType=\"centerInside\"\n            android:layout_weight=\"2\"\n            android:src=\"@drawable/card_unknown_logo\" />\n    </LinearLayout>\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginTop=\"10dp\"\n        android:orientation=\"horizontal\">\n\n        <com.worldpay.access.checkout.ui.AccessCheckoutEditText\n            android:id=\"@+id/expiry_date_input\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:ems=\"4\"\n            android:hint=\"Expiry date\"\n            android:imeOptions=\"actionDone|flagNoFullscreen\"\n            android:inputType=\"text\" />\n\n        <com.worldpay.access.checkout.ui.AccessCheckoutEditText\n            android:id=\"@+id/cvc_input\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"20dp\"\n            android:layout_weight=\"1\"\n            android:ems=\"4\"\n            android:hint=\"CVC\"\n            android:imeOptions=\"actionDone|flagNoFullscreen\"\n            android:inputType=\"text\" />\n    </LinearLayout>\n</LinearLayout>"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"ios-create-custom-view","__idx":9},"children":["iOS: create custom view"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AppDelegate.swift"]}," - the entry point responsible for registering the ViewFactory and binding the ViewFactory to"," ","a platform channel."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutView.swift"]}," - renders the Access Checkout UI, handles session generation and validation and communicates"," ","to Flutter via the Method Channel."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutViewFactory.swift"]}," - creates and configures instances of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutView"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutViewController.swift"]}," - manages the layout in storyboard and connects the UI elements."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutView.storyboard"]}," - contains the UI layout of the Access Checkout fields (Pan, Expiry and CVC)."," ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]}]}]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"AppDelegate.swift","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/iOS/AppDelegate.swift","language":"swift","title":"ios/Runner/AppDelegate.swift","header":{"title":"ios/Runner/AppDelegate.swift","controls":{"copy":{}}},"lang":"swift","source":"import Flutter\nimport UIKit\n\n@main\n@objc class AppDelegate: FlutterAppDelegate {\n    private var METHOD_CHANNEL_NAME = \"com.worldpay.flutter/accesscheckout\"\n\n    override func application(\n        _ application: UIApplication,\n        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n    ) -> Bool {\n        GeneratedPluginRegistrant.register(with: self)\n\n        weak var pluginRegistrar = registrar(forPlugin: \"com.worldpay.flutter/accesscheckout\")\n        \n        let factory = AccessCheckoutViewFactory(\n            messenger: pluginRegistrar!.messenger(),\n            channel: METHOD_CHANNEL_NAME)\n        \n        pluginRegistrar!.register(\n            factory,\n            withId: \"com.worldpay.flutter/accesscheckout\"\n    \n        )\n        return super.application(application, didFinishLaunchingWithOptions: launchOptions)\n    }\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"AccessCheckoutView.swift","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/iOS/AccessCheckoutView.swift","language":"swift","title":"ios/Runner/AccessCheckoutView.swift","header":{"title":"ios/Runner/AccessCheckoutView.swift","controls":{"copy":{}}},"lang":"swift","source":"import AccessCheckoutSDK\nimport Flutter\nimport UIKit\n\nclass AccessCheckoutView: NSObject, FlutterPlatformView {\n    @IBOutlet private var panInput: AccessCheckoutUITextField!\n    @IBOutlet private var expiryInput: AccessCheckoutUITextField!\n    @IBOutlet private var cvcInput: AccessCheckoutUITextField!\n    private var accessCheckoutClient: AccessCheckoutClient\n    private var methodChannel: FlutterMethodChannel\n    private var _view: UIView\n\n    private var baseUrl: String\n    private var checkoutId: String\n    private var useCardValidation: Bool\n\n    private var controller: AccessCheckoutViewController\n\n\n    init(\n        methodChannel channel: FlutterMethodChannel,\n        frame: CGRect,\n        viewIdentifier viewId: Int64,\n        binaryMessenger messenger: FlutterBinaryMessenger?,\n        creationParams: [String: Any]\n    ) {\n        baseUrl = creationParams[\"baseUrl\"] as? String ?? \"\"\n        checkoutId = creationParams[\"checkoutId\"] as? String ?? \"\"\n        useCardValidation = creationParams[\"useCardValidation\"] as? Bool ?? false\n        methodChannel = channel\n\n        accessCheckoutClient = try! AccessCheckoutClientBuilder()\n            .accessBaseUrl(baseUrl)\n            .checkoutId(checkoutId)\n            .build()\n\n        let storyboard = UIStoryboard(name: \"AccessCheckoutView\", bundle: Bundle.main)\n        controller = storyboard.instantiateViewController(withIdentifier:\"ViewController\") as! AccessCheckoutViewController\n\n        _view = controller.view!\n\n        super.init()\n\n        methodChannel.setMethodCallHandler({\n            [weak self] (call, result) in\n            guard let self = self else {return}\n\n            switch call.method{\n            case \"generateSession\":\n                generateSession()\n            default:\n                result(FlutterMethodNotImplemented)\n\n            }\n        })\n\n        // iOS views can be created here\n        referenceNativeView()\n\n        if(useCardValidation){\n            initializeCardValidation()\n        }\n    }\n\n    func initializeCardValidation() {\n        let validationConfig = try! CardValidationConfig.builder()\n            .pan(panInput)\n            .expiryDate(expiryInput)\n            .cvc(cvcInput)\n            .accessBaseUrl(baseUrl)\n            .validationDelegate(self)\n            .enablePanFormatting()\n                .build()\n\n\n        AccessCheckoutValidationInitialiser().initialise(validationConfig)\n    }\n\n    func updateUIField(field: AccessCheckoutUITextField, isValid: Bool) {\n        var  colour = isValid ? UIColor.green : UIColor.red\n\n        //Update Text & border color\n        field.textColor = colour\n        field.borderColor = colour\n    }\n\n    func generateSession() {\n\n        let cardDetails = try! CardDetailsBuilder().pan(panInput)\n            .expiryDate(expiryInput)\n            .cvc(cvcInput)\n            .build()\n\n        do { try accessCheckoutClient.generateSessions(\n            cardDetails: cardDetails,\n            sessionTypes: [SessionType.card]) { result in\n                DispatchQueue.main.async {\n                    switch result {\n                    case .failure(let error):\n                        print(error)\n                        self.methodChannel.invokeMethod(\"onSessionError\", arguments: \"Could not create session\")\n                        \n                    case .success(let sessions):\n                        var sessionData: [String: String] = [:]\n                        for (key, value) in sessions {\n                            let keyName = String(describing: key).uppercased()\n                            sessionData[keyName] = value\n                        }\n                        self.methodChannel.invokeMethod(\"onSessionGenerated\", arguments: sessionData)\n                    }\n                }\n            }\n        }\n        catch {\n            self.methodChannel.invokeMethod(\"onSessionError\", arguments: \"Could not create session\")\n        }\n    }\n\n    func referenceNativeView() {\n        panInput = controller.panInput\n        expiryInput = controller.expiryInput\n        cvcInput = controller.cvcInput\n    }\n\n\n    func view() -> UIView {\n        return _view\n    }\n\n}\n\nextension AccessCheckoutView: AccessCheckoutCardValidationDelegate {\n    func cardBrandChanged(cardBrand: AccessCheckoutSDK.CardBrand?) {\n        //TODO\n    }\n\n    func panValidChanged(isValid: Bool) {\n        self.updateUIField(field: self.panInput, isValid: isValid)\n        if(!isValid){\n            self.methodChannel.invokeMethod(\"onValidationUpdated\", arguments:false)\n        }\n    }\n\n    func expiryDateValidChanged(isValid: Bool) {\n        self.updateUIField(field: self.expiryInput, isValid: isValid)\n        if(!isValid){\n            self.methodChannel.invokeMethod(\"onValidationUpdated\", arguments:false)\n        }\n    }\n\n    func cvcValidChanged(isValid: Bool) {\n        self.updateUIField(field: self.cvcInput, isValid: isValid)\n        if(!isValid){\n            self.methodChannel.invokeMethod(\"onValidationUpdated\", arguments:false)\n        }\n    }\n\n    func validationSuccess() {\n        self.methodChannel.invokeMethod(\"onValidationUpdated\", arguments:true)\n\n    }\n\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"AccessCheckoutViewFactory.swift","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/iOS/AccessCheckoutViewFactory.swift","language":"swift","title":"ios/Runner/AccessCheckoutViewFactory.swift","header":{"title":"ios/Runner/AccessCheckoutViewFactory.swift","controls":{"copy":{}}},"lang":"swift","source":"import Flutter\nimport UIKit\n\nclass AccessCheckoutViewFactory: NSObject, FlutterPlatformViewFactory {\n    private var messenger: FlutterBinaryMessenger\n    private var channel: String \n\n    init(messenger: FlutterBinaryMessenger, channel: String) {\n        self.messenger = messenger\n        self.channel = channel\n        super.init()\n    }\n\n    \n    func create(\n        withFrame frame: CGRect,\n        viewIdentifier viewId: Int64,\n        arguments args: Any?\n    ) -> FlutterPlatformView {\n        let creationParams = args as? [String: Any] ?? [:]\n        return AccessCheckoutView(\n            methodChannel: FlutterMethodChannel(name: channel, binaryMessenger: messenger),\n            frame: frame,\n            viewIdentifier: viewId,\n            binaryMessenger: messenger,\n            creationParams: creationParams\n        )\n    }\n    \n    /// Implementing this method is only necessary when the `arguments` in `createWithFrame` is not `nil`.\n    public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {\n        return FlutterStandardMessageCodec.sharedInstance()\n    }\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"AccessCheckoutViewController.swift","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/iOS/AccessCheckoutViewController.swift","language":"swift","title":"ios/Runner/AccessCheckoutViewController.swift","header":{"title":"ios/Runner/AccessCheckoutViewController.swift","controls":{"copy":{}}},"lang":"swift","source":"import AccessCheckoutSDK\nimport Flutter\nimport UIKit\n\nclass AccessCheckoutViewController: UIViewController {\n    @IBOutlet weak var panInput: AccessCheckoutUITextField!\n    @IBOutlet weak var cvcInput: AccessCheckoutUITextField!\n    @IBOutlet weak var expiryInput: AccessCheckoutUITextField!\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"AccessCheckoutView.storyboard","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/implement-native-views/iOS/AccessCheckoutView.storyboard","language":"xml","title":"ios/Runner/AccessCheckoutView.storyboard","header":{"title":"ios/Runner/AccessCheckoutView.storyboard","controls":{"copy":{}}},"lang":"xml","source":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"23504\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"23506\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Access Checkout View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController storyboardIdentifier=\"ViewController\" id=\"BYZ-38-t0r\" customClass=\"AccessCheckoutViewController\" customModule=\"Runner\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"hy8-fq-jdj\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"P4U-sM-I5g\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uOE-eK-LJK\" userLabel=\"Pan\" customClass=\"AccessCheckoutUITextField\" customModule=\"AccessCheckoutSDK\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"375\" height=\"45\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                <accessibility key=\"accessibilityConfiguration\" identifier=\"pan\" label=\"Pan\">\n                                    <bool key=\"isElement\" value=\"YES\"/>\n                                </accessibility>\n                                <userDefinedRuntimeAttributes>\n                                    <userDefinedRuntimeAttribute type=\"string\" keyPath=\"placeholder\" value=\"Card Number\"/>\n                                </userDefinedRuntimeAttributes>\n                            </view>\n                            <view contentMode=\"scaleToFill\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ts8-Kj-GhN\" userLabel=\"Expiry date\" customClass=\"AccessCheckoutUITextField\" customModule=\"AccessCheckoutSDK\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"73\" width=\"231\" height=\"45\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                <accessibility key=\"accessibilityConfiguration\" identifier=\"expiryDate\" label=\"Expiry date\">\n                                    <bool key=\"isElement\" value=\"YES\"/>\n                                </accessibility>\n                                <userDefinedRuntimeAttributes>\n                                    <userDefinedRuntimeAttribute type=\"string\" keyPath=\"placeholder\" value=\"Expiry Date\"/>\n                                </userDefinedRuntimeAttributes>\n                            </view>\n                            <view contentMode=\"scaleToFill\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A4Q-yr-qYy\" userLabel=\"Cvc\" customClass=\"AccessCheckoutUITextField\" customModule=\"AccessCheckoutSDK\">\n                                <rect key=\"frame\" x=\"239\" y=\"73\" width=\"136\" height=\"45\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                <accessibility key=\"accessibilityConfiguration\" identifier=\"cvc\" label=\"Cvc\">\n                                    <bool key=\"isElement\" value=\"YES\"/>\n                                </accessibility>\n                                <userDefinedRuntimeAttributes>\n                                    <userDefinedRuntimeAttribute type=\"string\" keyPath=\"placeholder\" value=\"CVC\"/>\n                                </userDefinedRuntimeAttributes>\n                            </view>\n                        </subviews>\n                    </view>\n                    <connections>\n                        <outlet property=\"cvcInput\" destination=\"A4Q-yr-qYy\" id=\"N9y-q9-Abt\"/>\n                        <outlet property=\"expiryInput\" destination=\"ts8-Kj-GhN\" id=\"V4f-nQ-htV\"/>\n                        <outlet property=\"panInput\" destination=\"uOE-eK-LJK\" id=\"uvL-eo-qJW\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-698.39999999999998\" y=\"831.63418290854577\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"on-the-flutter-side","__idx":10},"children":["On the Flutter side"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"set-up-method-channels-for-communication","__idx":11},"children":["Set up method channels for communication"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To communicate with the native side you must create a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["service"]}," that handles the communication between Flutter and Native."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In this class, you connect to our previously defined method channel ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.worldpay.flutter/accesscheckout"]}," on the Native"," ","iOS and Android platforms."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You must tell Flutter how to handle the callbacks issues when invoking the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["generateSession"]}," method on the native side."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Optionally you can also define the logic for handling validation updates, in case you would like to handle states."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Prerequisite"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The name of the method channel and methods must be the same between the Flutter and Native sides."," ","We are using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["com.worldpay.flutter/accesscheckout"]}," as the method channel and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["generateSession"]}," as the method name, as an example."]}]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"access_checkout_flutter.dart","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/method-channels/access_checkout_flutter.dart","language":"java","title":"lib/service/access_checkout_flutter.dart","header":{"title":"lib/service/access_checkout_flutter.dart","controls":{"copy":{}}},"lang":"java","source":"import 'package:flutter/services.dart';\n\nclass AccessCheckoutFlutter {\n  static const channel = MethodChannel('com.worldpay.flutter/accesscheckout');\n\n  static Future<void> listenForValidationUpdates(Function(bool) onValidationUpdated) async {\n    channel.setMethodCallHandler((call) async {\n      if (call.method case \"onValidationUpdated\") {\n        onValidationUpdated(call.arguments as bool);\n      }\n    });\n  }\n\n  static Future<void> generateSession(\n      {required Function(Map<dynamic, dynamic>) onSuccess,\n      required Function(String) onError}) async {\n    channel.setMethodCallHandler((call) async {\n      switch (call.method) {\n        case \"onSessionGenerated\":\n          onSuccess(call.arguments);\n\n        case \"onSessionError\":\n          onError(call.arguments);\n      }\n    });\n\n    await channel.invokeMethod<String>('generateSession');\n  }\n}\n"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"embed-native-views-in-flutter","__idx":12},"children":["Embed native views in Flutter"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To render our native views, you must handle the target platform and display a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PlatformViewLink"]}," for Android or a"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UiKitView"]}," for iOS."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["We recommend to create a widget to handle this logic ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["lib/widgets/access_checkout_native_widget.dart"]},","," ","so that this widget is the only one responsible for rendering the native views."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"access_checkout_native_widget.dart","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/embed-view/access_checkout_native_widget.dart","language":"java","title":"lib/widgets/access_checkout_native_widget.dart","header":{"title":"lib/widgets/access_checkout_native_widget.dart","controls":{"copy":{}}},"lang":"java","source":"import 'package:flutter/foundation.dart';\nimport 'package:flutter/gestures.dart';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter/services.dart';\n\nclass AccessCheckoutNativeWidget extends StatelessWidget {\n  final String checkoutId;\n  final String baseUrl;\n  final bool useCardValidation;\n\n  const AccessCheckoutNativeWidget({\n    super.key,\n    required this.checkoutId,\n    required this.baseUrl,\n    required this.useCardValidation,\n  });\n\n  static const StandardMessageCodec _decoder = StandardMessageCodec();\n\n  @override\n  Widget build(BuildContext context) {\n    const String viewType = \"com.worldpay.flutter/accesscheckout\";\n    final Map<String, dynamic> creationParams = <String, dynamic>{\n      \"baseUrl\": baseUrl,\n      \"checkoutId\": checkoutId,\n      \"useCardValidation\": useCardValidation\n    };\n\n    switch (defaultTargetPlatform) {\n      case TargetPlatform.android:\n\n  return PlatformViewLink(\n    viewType: viewType,\n    surfaceFactory: (context, controller) {\n      return AndroidViewSurface(\n        controller: controller as AndroidViewController,\n        gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},\n        hitTestBehavior: PlatformViewHitTestBehavior.opaque,\n      );\n    },\n    onCreatePlatformView: (params) {\n      return PlatformViewsService.initSurfaceAndroidView(\n          id: params.id,\n          viewType: viewType,\n          layoutDirection: TextDirection.ltr,\n          creationParams: creationParams,\n          creationParamsCodec: _decoder,\n          onFocus: () {\n            params.onFocusChanged(true);\n          },\n        )\n        ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)\n        ..create();\n    },\n  );\n      case TargetPlatform.iOS:\n        return UiKitView(\n          viewType: viewType,\n          layoutDirection: TextDirection.ltr,\n          creationParams: creationParams,\n          creationParamsCodec: const StandardMessageCodec(),\n        );\n      default:\n        throw UnsupportedError(\"Unsupported platform view\");\n    }\n  }\n}\n"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"render-the-flutter-component","__idx":13},"children":["Render the Flutter component"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can now render our newly created widget that integrates our Native Checkout SDKs into Flutter."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To achieve this, create another widget where you can orchestrate, render and handle some state for when a session is created."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This widget will also be responsible for initializing and configuring the SDKs, using parameters such as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["checkoutId"]},","," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["baseUrl"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["useCardValidation"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Finally, you must display this ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AccessCheckoutWidget"]}," in our Flutter page and configure the parameters it requires."," ",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"native_sdk_page.dart","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/render-flutter-component/native_sdk_page.dart","language":"java","title":"lib/screens/native_sdk_page.dart","header":{"title":"lib/screens/native_sdk_page.dart","controls":{"copy":{}}},"lang":"java","source":"import 'package:access_checkout_flutter_native_sdk_demo/widgets/access_checkout.dart';\nimport 'package:flutter/material.dart';\n\nclass NativeSdkPage extends StatelessWidget {\n  const NativeSdkPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return const Center(\n        child: AccessCheckoutWidget(\n            // TODO: Replace the checkout id and base url with the values provided to you\n            checkoutId: \"00000000-0000-0000-0000-000000000000\",\n            baseUrl: \"https://try.access.worldpay.com\",\n            useCardValidation: true));\n  }\n}\n"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"access_checkout.dart","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"file":"./code/native-sdk/render-flutter-component/access_checkout.dart","language":"java","title":"lib/widgets/access_checkout.dart","header":{"title":"lib/widgets/access_checkout.dart","controls":{"copy":{}}},"lang":"java","source":"import 'package:access_checkout_flutter_native_sdk_demo/service/access_checkout_flutter.dart';\nimport 'package:access_checkout_flutter_native_sdk_demo/widgets/access_checkout_native_widget.dart';\nimport 'package:flutter/material.dart';\n\nclass AccessCheckoutWidget extends StatefulWidget {\n  final String checkoutId;\n  final String baseUrl;\n  final bool useCardValidation;\n\n  const AccessCheckoutWidget({\n    super.key,\n    required this.checkoutId,\n    required this.baseUrl,\n    required this.useCardValidation,\n  });\n\n  @override\n  AccessCheckoutWidgetState createState() => AccessCheckoutWidgetState();\n}\n\nclass AccessCheckoutWidgetState extends State<AccessCheckoutWidget> {\n  bool isSubmitButtonEnabled = false;\n  String sessionToken = \"\";\n  late String checkoutId;\n  late String baseUrl;\n  late bool useCardValidation;\n\n  @override\n  void initState() {\n    super.initState();\n    checkoutId = widget.checkoutId;\n    baseUrl = widget.baseUrl;\n    useCardValidation = widget.useCardValidation;\n\n    if (useCardValidation) {\n      AccessCheckoutFlutter.listenForValidationUpdates((isInputValid) {\n        setState(() {\n          isSubmitButtonEnabled = isInputValid;\n        });\n      });\n    } else {\n      setState(() {\n        isSubmitButtonEnabled = true;\n      });\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n        body: Padding(\n            padding: const EdgeInsets.all(20),\n            child: Column(\n              crossAxisAlignment: CrossAxisAlignment.center,\n              children: [\n                SizedBox(\n                    height: 150,\n                    child: AccessCheckoutNativeWidget(\n                        checkoutId: checkoutId,\n                        baseUrl: baseUrl,\n                        useCardValidation: useCardValidation)),\n                Row(children: <Widget>[\n                  Expanded(\n                    flex: 1,\n                    child: OutlinedButton(\n                      onPressed: isSubmitButtonEnabled\n                          ? () => generateSession()\n                          : null,\n                      child: const Text('Submit'),\n                    ),\n                  )\n                ]),\n                if (sessionToken != \"\") Text(sessionToken),\n              ],\n            )));\n  }\n\n  Future<void> generateSession() async {\n    await AccessCheckoutFlutter.generateSession(onSuccess: (sessions) {\n      setState(() {\n        sessionToken = sessions[\"CARD\"]!;\n      });\n      showSnackBar(sessions[\"CARD\"]!);\n    }, onError: (error) {\n      showSnackBar(error);\n    });\n  }\n\n  void showSnackBar(String message) {\n    ScaffoldMessenger.of(context).showSnackBar(\n        SnackBar(content: Text(message), duration: const Duration(seconds: 5)));\n  }\n}\n"},"children":[]}]}]}]},"headings":[{"value":"Flutter integration with Native SDKs","id":"flutter-integration-with-native-sdks","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Get started","id":"get-started","depth":2},{"value":"On the Native side","id":"on-the-native-side","depth":2},{"value":"Add our iOS and Android Checkout SDK","id":"add-our-ios-and-android-checkout-sdk","depth":3},{"value":"Android: add SDK dependency","id":"android-add-sdk-dependency","depth":4},{"value":"iOS: add SDK dependency","id":"ios-add-sdk-dependency","depth":4},{"value":"Implement native views","id":"implement-native-views","depth":3},{"value":"Android: create custom view","id":"android-create-custom-view","depth":4},{"value":"iOS: create custom view","id":"ios-create-custom-view","depth":4},{"value":"On the Flutter side","id":"on-the-flutter-side","depth":2},{"value":"Set up method channels for communication","id":"set-up-method-channels-for-communication","depth":3},{"value":"Embed native views in Flutter","id":"embed-native-views-in-flutter","depth":3},{"value":"Render the Flutter component","id":"render-the-flutter-component","depth":3}],"frontmatter":{"seo":{"title":"Flutter integration with Native SDKs"}},"lastModified":"2025-09-22T09:15:26.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/products/checkout/flutter/native-sdk","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}