Flutter功能扩展插件tuna_sdk的应用

Flutter功能扩展插件tuna_sdk的应用

插件tuna_sdk特性

  • Tokenization方法:您可以调用 /Generate, /Bind, /Delete, /List
  • 3DS方法:允许您创建一个更安全的支付步骤。

Flutter功能扩展插件tuna_sdk使用方法

Tokenization示例
var tokenizer = await Tokenizer.create('a3823a59-66bb-49e2-95eb-b47c447ec7a7', 'demo', customer, "14", env: "sandbox");
var cardData = CardData(cardNumber: "4756169062715850", cardHolderName: "Example Card", expirationMonth: 10, expirationYear: 2025, cvv: "257");
var generateResponse = await tokenizer.generate(cardData);
3DS示例
_threeDS = ThreeDS(
  (message) async {
    if (message == "Data collection ready") {
      var initResponse = await callInit(generateResponse, _cardData);
      var threeDSInfo = ThreeDSInfo.fromJson(initResponse["methods"][0]["threeDSInfo"]);
      _threeDS.loadChallengeFrame(threeDSInfo);
    }
  },
);

_threeDS.loadDataCollectionFrame(generateResponse.authenticationInformation!.accessToken!, generateResponse.authenticationInformation!.deviceDataCollectionUrl!);

完整示例

完整的示例代码可以在 tuna_sdk_test.dart 中找到。要查看3DS支付方法,可以运行 /example 文件夹下的示例Flutter应用。

示例代码

以下是完整的示例代码:

// ignore_for_file: avoid_print
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:tuna_sdk/tuna_sdk.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:dio/dio.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tuna SDK Test App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Tuna SDK Test App'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final Dio _dio = Dio();

  late final ThreeDS _threeDS;
  late final Tuna _tuna;
  bool _showThreeDS = false;
  bool _dataLoaded = false;
  String _infoText = "Starting app";

  // -------------// Edit this data //-------------//
  final String _env = "prod";
  final CustomerData _customer = CustomerData("4321", "john.doe@tuna.uy");
  final String _partnerUniqueId = _generateRandomString(10);
  final CardData _cardData = CardData(
      cardNumber: "4456530000001096",
      cardHolderName: "John Doe",
      expirationMonth: 1,
      expirationYear: 2027,
      cvv: "123");

  // Sensitive data
  final String _appToken = "";
  final String _account = "";
  // Sensitive data

  // -------------// Edit this data //-------------//

  static String _generateRandomString(int i) =>
      String.fromCharCodes(List.generate(
          i,
          (_) =>
              'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
                  .codeUnitAt(Random().nextInt(62))));

  void callDialog(String message) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('3DS result'),
          content: Text(message),
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text('Close'),
            ),
          ],
        );
      },
    );
  }

  Future<void> startPaymentTransaction() async {
    _tuna = await Tuna.create(_appToken, _account, _customer, _partnerUniqueId,
        env: _env, is3dsTest: true);

    setState(() {
      _infoText = "Tuna object created";
    });

    var generateResponse = await _tuna.tokenizer.generate(_cardData);

    setState(() {
      _infoText = "Card token generated. \n SessionID: ${_tuna.sessionID}";
    });

    _threeDS = ThreeDS(
      (message) async {
        if (message == "Data collection ready") {
          setState(() {
            _infoText = "3DS data collection done. Calling /Init";
          });
          final initResponse = await callInit(generateResponse, _cardData);

          setState(() {
            _infoText = "/Init call ended. 3DS challenge loading";
          });

          final paymentMethod = initResponse["methods"][0];
          final threeDSInfo =
              ThreeDSInfo.fromJson(paymentMethod["threeDSInfo"]);

          setState(() {
            _showThreeDS = true;
          });

          _threeDS.loadChallengeFrame(threeDSInfo);

          _tuna.doStatusLongPolling((statusPollResult) {
            if (statusPollResult.code == 1) {
              if (statusPollResult.paymentMethodConfirmed) {
                if (statusPollResult.paymentApproved ?? false) {
                  setState(() {
                    _showThreeDS = false;
                    _infoText = "3DS payment ended";
                  });
                  callDialog("Payment approved!");
                } else {
                  callDialog("Payment refused");
                }
              } else {
                // callDialog("Error");
              }
            } else {
              // callDialog("Error");
            }
          }, paymentMethod["methodId"], initResponse["paymentKey"]);
        } else if (message == "Challenge done") {
          setState(() {
            _showThreeDS = false;
            _infoText = """
The challenge is done and the Webview is closed now.
This does not mean that the purchase was approved,
it only means that the challenge was completed.
To know if the payment was approved,
check the payment status.
""";
          });
        }
      },
    );

    final authenticationInfo = generateResponse.authenticationInformation!;
    final accessToken = authenticationInfo.accessToken!;
    final deviceDataCollectionUrl = authenticationInfo.deviceDataCollectionUrl!;

    _threeDS.loadDataCollectionFrame(accessToken, deviceDataCollectionUrl);
    setState(() {
      _infoText =
          "3DS device data collection is running. \n Take a look at console output. \n The webview is invisible this moment";
    });
  }

  Future<dynamic> callInit(
      GenerateResponse generateResponse, CardData cardData) async {
    try {
      Response response = await _dio.post(
        'https://engine.tunagateway.com/api/Payment/Init',
        options: Options(
          headers: {
            'accept': 'application/json',
            'x-tuna-account': _account,
            'x-tuna-apptoken': _appToken,
            'Content-Type': 'application/json',
            'Idempotency-Key': 'YzHfUsJHm73412df',
          },
        ),
        data: {
          "PartnerUniqueID": _partnerUniqueId,
          "TokenSession": _tuna.sessionID,
          "Customer": {
            "Email": _customer.email,
            "ID": _customer.id,
            "Document": "160.756.340-10",
            "DocumentType": "CPF"
          },
          "FrontData": {
            "SessionID": "3ca3cc8ff8eac0093a4097de219f2a8c",
            "Origin": "WEBSITE",
            "IpAddress": "172.18.0.1",
            "CookiesAccepted": true
          },
          "PaymentItems": {
            "Items": [
              {
                "Amount": 10,
                "ProductDescription": "Sample Product",
                "ItemQuantity": 1,
                "CategoryName": "simple",
                "AntiFraud": {"Ean": "24-WB04"}
              }
            ]
          },
          "PaymentData": {
            "Countrycode": "BR",
            "DeliveryAddress": {
              "Street": "Sample Street",
              "Number": "288",
              "City": "Salvador",
              "State": "BA",
              "Country": "BR",
              "PostalCode": "41341-545",
              "Phone": "(71)999999929"
            },
            "SalesChannel": "ECOMMERCE",
            "Amount": 10,
            "PaymentMethods": [
              {
                "PaymentMethodType": "7",
                "Amount": 10,
                "Installments": 1,
                "cardInfo": {
                  "CardNumber": cardData.cardNumber,
                  "CardHolderName": cardData.cardHolderName,
                  "BrandName": generateResponse.brand,
                  "ExpirationMonth": cardData.expirationMonth,
                  "ExpirationYear": cardData.expirationYear,
                  "Token": generateResponse.token,
                  "TokenProvider": "Tuna",
                  "TokenSingleUse": cardData.singleUse,
                  "SaveCard": !(cardData.singleUse ?? true),
                  "BillingInfo": {
                    "Document": "160.756.340-10",
                    "DocumentType": "CPF",
                    "Address": {}
                  }
                },
                "AuthenticationInformation": {
                  "Code": _tuna.sessionID,
                  "ReferenceId":
                      generateResponse.authenticationInformation!.referenceId!,
                  "TransactionId":
                      generateResponse.authenticationInformation!.transactionId!
                }
              }
            ]
          }
        },
      );

      return response.data;
    } catch (error, stacktrace) {
      print('Error: $error, Stacktrace: $stacktrace');
    }
  }

  [@override](/user/override)
  void initState() {
    super.initState();
    startPaymentTransaction().then((_) => setState(() => _dataLoaded = true));
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Wrap(
            spacing: 5.0,
            runSpacing: 5.0,
            direction: Axis.vertical,
            children: [
              Visibility(
                  visible: !_showThreeDS,
                  child: Center(
                    child: Text(_infoText),
                  )),
              _dataLoaded
                  ? SizedBox(
                      width: MediaQuery.of(context).size.width,
                      height: MediaQuery.of(context).size.height,
                      child: SizedBox.expand(
                          child: Visibility(
                              visible: _showThreeDS,
                              child: WebViewWidget(
                                  controller: _threeDS.webViewController))))
                  : Container(),
            ],
          ),
        ));
  }
}

更多关于Flutter功能扩展插件tuna_sdk的应用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter功能扩展插件tuna_sdk的应用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


由于tuna_sdk是一个未明确文档化或广泛认知的Flutter插件,以下内容将基于一般Flutter插件的使用方式以及可能的插件功能进行合理推测,并提供一个假设性的代码案例。请注意,实际使用时需要根据tuna_sdk的真实功能和API进行调整。

假设性的tuna_sdk插件功能

假设tuna_sdk是一个用于扩展Flutter应用功能的插件,可能提供了一些高级功能,如数据加密、设备硬件访问、或者特定的第三方服务集成等。

插件安装

首先,你需要在pubspec.yaml文件中添加对tuna_sdk的依赖(假设它已经在pub.dev上发布,或者你已经将其作为一个本地插件):

dependencies:
  flutter:
    sdk: flutter
  tuna_sdk: ^x.y.z  # 替换为实际的版本号

然后运行flutter pub get来安装插件。

导入插件

在你的Dart文件中导入tuna_sdk

import 'package:tuna_sdk/tuna_sdk.dart';

假设性的功能使用代码案例

假设功能1:数据加密

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Tuna SDK Demo'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              // 假设TunaSDK有一个encrypt方法用于数据加密
              String plainText = "Hello, Tuna SDK!";
              String encryptedText = await TunaSDK.encrypt(plainText);
              print("Encrypted Text: $encryptedText");
            },
            child: Text('Encrypt Text'),
          ),
        ),
      ),
    );
  }
}

在这个假设性的例子中,我们假设TunaSDK类有一个静态的encrypt方法,用于将明文加密。

假设功能2:设备硬件访问(如摄像头)

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Tuna SDK Demo'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              // 假设TunaSDK有一个captureImage方法用于从摄像头捕获图像
              File? imageFile = await TunaSDK.captureImage();
              if (imageFile != null) {
                // 显示或处理捕获的图像
                print("Image captured and saved to ${imageFile.path}");
              } else {
                print("Failed to capture image");
              }
            },
            child: Text('Capture Image'),
          ),
        ),
      ),
    );
  }
}

在这个例子中,我们假设TunaSDK类有一个静态的captureImage方法,用于从设备摄像头捕获图像并返回一个File对象。

注意事项

  • 由于tuna_sdk的具体功能和API未知,上述代码仅为假设性示例。
  • 在实际使用时,应参考tuna_sdk的官方文档或源代码以了解其功能和使用方法。
  • 如果tuna_sdk是一个私有或内部插件,请确保你有权限访问其文档和源代码。

希望这些假设性的代码案例能帮助你理解如何在Flutter中使用一个未知的插件。如果有更多关于tuna_sdk的具体信息,可以进一步调整和优化代码。

回到顶部