我正在flutter中使用stripe终端android SDK https://docs.stripe.com/terminal/quickstart?reader=wp3,因为没有适用于Flutter的SDK。我尝试了很多天。 Stripe 终端已初始化,但未检测到 Wisepad 3 读卡器。
颤动代码=
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class BluetoothConfigurationScreen extends StatefulWidget {
const BluetoothConfigurationScreen({super.key});
@override
State<BluetoothConfigurationScreen> createState() =>
_BluetoothConfigurationScreenState();
}
class _BluetoothConfigurationScreenState
extends State<BluetoothConfigurationScreen> {
static const platform = MethodChannel('com.example.case/stripe');
TextEditingController textEditingController = TextEditingController();
String resultText = '';
String _batteryLevel = 'Unknown battery level.';
String _cardInfo = 'No card scanned';
String _connectedDeviceInfo = 'No device connected';
bool isTerminalInitialized = false;
bool isReaderConnected = false;
// Method to initialize Stripe terminal
Future<void> _initializeStripe() async {
try {
// Initialize the Stripe terminal by invoking the method on the native side
final result = await platform.invokeMethod('initializeStripe');
setState(() {
isTerminalInitialized = true; // Mark terminal as initialized
});
print(result);
} catch (e) {
setState(() {
isTerminalInitialized = false; // Handle initialization failure
});
print("Error initializing terminal: $e");
}
}
// Method to get battery level
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final result = await platform.invokeMethod<int>('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
// Method to start card scan
Future<void> _startCardScan() async {
if (!isTerminalInitialized || !isReaderConnected) {
setState(() {
_cardInfo = 'Terminal or Reader is not connected. Please initialize and connect first.';
});
return;
}
try {
final cardData = await platform.invokeMethod('scanCard');
setState(() {
_cardInfo = cardData;
});
} catch (e) {
setState(() {
_cardInfo = 'Error scanning card: $e';
});
}
}
// Method to discover Bluetooth devices and fetch connected device info
Future<void> _discoverReaders() async {
if (!isTerminalInitialized) {
setState(() {
_cardInfo = 'Terminal is not initialized yet. Please initialize first.';
});
return;
}
try {
final result = await platform.invokeMethod('discoverReaders');
setState(() {
_cardInfo = result;
isReaderConnected = true; // Assuming reader is connected after discovery
});
// Fetch connected device info
final connectedDevice = await platform.invokeMethod('getConnectedDeviceInfo');
setState(() {
_connectedDeviceInfo = connectedDevice ?? 'No connected device information available';
});
} catch (e) {
setState(() {
_cardInfo = 'Error discovering readers: $e';
isReaderConnected = false;
_connectedDeviceInfo = 'Error fetching connected device info';
});
}
}
// Method to make a 0.1 cent payment
Future<void> _makePayment() async {
if (!isTerminalInitialized || !isReaderConnected) {
setState(() {
_cardInfo = 'Terminal or Reader is not connected. Please initialize and connect first.';
});
return;
}
try {
final paymentResult = await platform.invokeMethod('makePayment');
setState(() {
_cardInfo = paymentResult;
});
} catch (e) {
setState(() {
_cardInfo = 'Error processing payment: $e';
});
}
}
@override
void dispose() {
textEditingController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () async {
await _initializeStripe(); // Initialize Stripe Terminal
if (isTerminalInitialized) {
setState(() {
_cardInfo = "Terminal Initialized. You can now scan cards.";
});
} else {
setState(() {
_cardInfo = "Initialization failed. Try again.";
});
}
},
child: const Text("Initialize Stripe Terminal"),
),
const SizedBox(height: 30),
ElevatedButton(
onPressed: _getBatteryLevel,
child: const Text('Get Battery Level'),
),
Text(_batteryLevel),
const SizedBox(height: 30),
ElevatedButton(
onPressed: _startCardScan, // Trigger card scan
child: const Text('Scan Card'),
),
Text(_cardInfo), // Display scanned card information
const SizedBox(height: 30),
ElevatedButton(
onPressed: _discoverReaders, // Discover Bluetooth readers
child: const Text('Discover Bluetooth Readers'),
),
Text(_cardInfo), // Display reader information
Text('Connected Device Info: $_connectedDeviceInfo'), // Display connected device info
const SizedBox(height: 30),
ElevatedButton(
onPressed: _makePayment, // Trigger payment of 0.1 cent
child: const Text('Make 0.1 Cent Payment'),
),
Text(_cardInfo), // Display payment result
const SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: TextField(
controller: textEditingController,
decoration: const InputDecoration(
labelText: 'Enter UserName',
),
),
),
const SizedBox(height: 30),
ElevatedButton(
onPressed: () async {
final userName = textEditingController.text;
await callNativeCode(userName);
setState(() {});
},
child: const Text('Send Data'),
),
Text(resultText),
],
),
),
);
}
// Method to send user data to the native code
Future<void> callNativeCode(String userName) async {
try {
resultText =
await platform.invokeMethod('userName', {'username': userName});
setState(() {});
} catch (e) {
print("Failed to send user data: $e");
}
}
}
安卓代码=
package com.example.np_casse
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.BatteryManager
import androidx.annotation.NonNull
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import com.stripe.stripeterminal.Terminal
import com.stripe.stripeterminal.external.callable.*
import com.stripe.stripeterminal.external.models.*
import com.stripe.stripeterminal.log.LogLevel
import android.util.Log
import com.stripe.stripeterminal.external.models.Reader
class MainActivity : FlutterActivity() {
private val CHANNEL = "com.example.case/stripe"
private var terminalInitialized = false
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
"initializeStripe" -> initializeTerminal(result)
"discoverReaders" -> {
if (terminalInitialized) {
discoverReaders(result)
} else {
result.error("TERMINAL_NOT_INITIALIZED", "Terminal must be initialized first", null)
}
}
"scanCard" -> {
if (terminalInitialized) {
startCardScan(result)
} else {
result.error("TERMINAL_NOT_INITIALIZED", "Terminal must be initialized first", null)
}
}
"makePayment" -> {
if (terminalInitialized) {
makePayment(result)
} else {
result.error("TERMINAL_NOT_INITIALIZED", "Terminal must be initialized first", null)
}
}
"getBatteryLevel" -> getBatteryLevel(result)
"getConnectedDeviceInfo" -> getConnectedDeviceInfo(result) // Fetch device info
else -> result.notImplemented()
}
}
}
private fun initializeTerminal(result: MethodChannel.Result) {
if (!Terminal.isInitialized()) {
try {
Terminal.initTerminal(applicationContext, LogLevel.VERBOSE, TokenProvider(), TerminalEventListener())
terminalInitialized = true
result.success("Stripe Initialized")
} catch (e: TerminalException) {
terminalInitialized = false
result.error("INITIALIZATION_ERROR", "Error initializing Terminal: ${e.message}", null)
}
} else {
terminalInitialized = true
result.success("Stripe Already Initialized")
}
}
private fun discoverReaders(result: MethodChannel.Result) {
if (checkLocationPermissions() && checkBluetoothPermissions()) {
val discoveryConfig = DiscoveryConfiguration.BluetoothDiscoveryConfiguration(isSimulated = false)
val discoveryCallback = object : Callback {
override fun onSuccess() {
result.success("Reader discovery started")
}
override fun onFailure(e: TerminalException) {
result.error("DISCOVERY_ERROR", e.message, null)
}
}
val discoveryListener = object : DiscoveryListener {
override fun onUpdateDiscoveredReaders(readers: List<Reader>) {
if (readers.isEmpty()) {
result.success("No readers detected.")
} else {
for (reader in readers) {
result.success("Reader found: ${reader.label}")
}
}
}
}
Terminal.getInstance().discoverReaders(discoveryConfig, discoveryListener, discoveryCallback)
} else {
requestPermissions()
}
}
// New method to get connected device info
private fun getConnectedDeviceInfo(result: MethodChannel.Result) {
val reader: Reader? = Terminal.getInstance().connectedReader
if (reader != null) {
val deviceInfo = "Label: ${reader.label}, Serial Number: ${reader.serialNumber}"
result.success(deviceInfo)
} else {
result.success("No reader connected")
}
}
private fun startCardScan(result: MethodChannel.Result) {
val reader = Terminal.getInstance().connectedReader
if (reader != null) {
val paymentIntentParams = PaymentIntentParameters.Builder(listOf(PaymentMethodType.CARD_PRESENT))
.setAmount(1)
.setCurrency("usd")
.build()
Terminal.getInstance().createPaymentIntent(paymentIntentParams, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
Terminal.getInstance().collectPaymentMethod(paymentIntent, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
Terminal.getInstance().confirmPaymentIntent(paymentIntent, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
result.success("Payment Successful")
}
override fun onFailure(e: TerminalException) {
result.error("PAYMENT_CONFIRM_ERROR", "Error confirming payment: ${e.message}", null)
}
})
}
override fun onFailure(e: TerminalException) {
result.error("PAYMENT_METHOD_ERROR", "Error collecting payment method: ${e.message}", null)
}
})
}
override fun onFailure(e: TerminalException) {
result.error("PAYMENT_INTENT_ERROR", "Error creating payment intent: ${e.message}", null)
}
})
} else {
result.error("NO_READER", "No reader connected", null)
}
}
private fun makePayment(result: MethodChannel.Result) {
val reader = Terminal.getInstance().connectedReader
if (reader != null) {
val paymentIntentParams = PaymentIntentParameters.Builder(listOf(PaymentMethodType.CARD_PRESENT))
.setAmount(1)
.setCurrency("usd")
.build()
Terminal.getInstance().createPaymentIntent(paymentIntentParams, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
Terminal.getInstance().collectPaymentMethod(paymentIntent, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
Terminal.getInstance().confirmPaymentIntent(paymentIntent, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
result.success("Payment Successful")
}
override fun onFailure(e: TerminalException) {
result.error("PAYMENT_CONFIRM_ERROR", "Error confirming payment: ${e.message}", null)
}
})
}
override fun onFailure(e: TerminalException) {
result.error("PAYMENT_METHOD_ERROR", "Error collecting payment method: ${e.message}", null)
}
})
}
override fun onFailure(e: TerminalException) {
result.error("PAYMENT_INTENT_ERROR", "Error creating payment intent: ${e.message}", null)
}
})
} else {
result.error("NO_READER", "No reader connected", null)
}
}
private fun getBatteryLevel(result: MethodChannel.Result) {
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
result.success(batteryLevel)
}
private fun checkLocationPermissions(): Boolean {
return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
private fun checkBluetoothPermissions(): Boolean {
return ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED
}
private fun requestPermissions() {
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH), 1
)
}
}
我尝试了不同的方法,但找不到任何解决方案。如果有人遇到同样的问题并且知道如何解决它,请告诉我。谢谢你
reader.label不存在。您可以检查serialNumber和deviceType。对我来说,它就是这样工作的=
if (checkPermissions()) {
if (BluetoothAdapter.getDefaultAdapter()?.isEnabled == false) {
BluetoothAdapter.getDefaultAdapter().enable()
}
val discoveryConfig = DiscoveryConfiguration.BluetoothDiscoveryConfiguration(isSimulated = false)
val discoveredReaders = mutableListOf<Reader>()
val discoveryListener = object : DiscoveryListener {
override fun onUpdateDiscoveredReaders(readers: List<Reader>) {
if (readers.isNotEmpty()) {
val firstReader = readers.first()
// Sending the first reader's details
val readerInfo = mapOf(
"serialNumber" to (firstReader.serialNumber ?: "Unknown"),
"deviceType" to (firstReader.deviceType.name ?: "Unknown")
)
// Send the first reader to Flutter
result.success(readerInfo)
} else {
result.success(null) // Send null if no readers are found
}
}
}