如何解决addPaymentMethod Stripe + Firebase Android
我正在尝试使用Firebase将Stripe添加到我的Android应用中。我在gradle.properties中设置了可发布密钥,并在gradle.build中设置了builtype,然后以BuildConfig.PublishableKey
每次我尝试添加卡时,都会弹出一个对话框,提示此警告...
9个标头值处的意外char 0x0a:承载pk_test_xxxxkeyxxxx
有什么想法吗?在他们的Firebase移动支付android之后,我也使用了来自Stripe的预构建UI(presentPaymentMethodSelection())
var RC_SIGN_IN = 1
class MainActivityStripe : AppCompatActivity() {
private var currentUser: FirebaseUser? = null
private lateinit var paymentSession: PaymentSession
private lateinit var selectedPaymentMethod: PaymentMethod
private val stripe: Stripe by lazy { Stripe(applicationContext,PaymentConfiguration.getInstance(applicationContext).publishableKey) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_stripe)
currentUser = FirebaseAuth.getInstance().currentUser
payButton.isEnabled = false
loginButton.setOnClickListener {
// login to firebase
val providers = arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build())
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.build(),RC_SIGN_IN
)
}
payButton.setOnClickListener {
confirmPayment(selectedPaymentMethod.id!!)
}
paymentmethod.setOnClickListener {
Toast.makeText(applicationContext,PaymentConfiguration.getInstance(applicationContext).publishableKey,Toast.LENGTH_LONG).show()
// Create the customer session and kick start the payment flow
paymentSession.presentPaymentMethodSelection()
}
showUI()
}
private fun confirmPayment(paymentMethodId: String) {
val paymentCollection = Firebase.firestore
.collection("stripe_customers").document(currentUser?.uid?:"")
.collection("payments")
// Add a new document with a generated ID
paymentCollection.add(hashMapOf(
"amount" to 8800,"currency" to "cad"
))
.addOnSuccessListener { documentReference ->
Log.d("paymentsss","DocumentSnapshot added with ID: ${documentReference.id}")
documentReference.addSnapshotListener { snapshot,e ->
if (e != null) {
Log.w("paymentsss","Listen failed.",e)
return@addSnapshotListener
}
if (snapshot != null && snapshot.exists()) {
Log.d("paymentsss","Current data: ${snapshot.data}")
val clientSecret = snapshot.data?.get("client_secret")
Log.d("paymentsss","Create paymentIntent returns $clientSecret")
clientSecret?.let {
stripe.confirmPayment(this,ConfirmPaymentIntentParams.createWithPaymentMethodId(
paymentMethodId,(it as String)
))
checkoutSummary.text = "Thank you for your payment"
Toast.makeText(applicationContext,"Payment Done!!",Toast.LENGTH_LONG).show()
}
} else {
Log.e("paymentsss","Current payment intent : null")
payButton.isEnabled = true
}
}
}
.addOnFailureListener { e ->
Log.w("paymentsss","Error adding document",e)
payButton.isEnabled = true
}
}
private fun showUI() {
currentUser?.let {
loginButton.visibility = View.INVISIBLE
greeting.visibility = View.VISIBLE
checkoutSummary.visibility = View.VISIBLE
payButton.visibility = View.VISIBLE
paymentmethod.visibility = View.VISIBLE
greeting.text = "Hello ${it.displayName}"
setupPaymentSession()
}?: run {
// User does not login
loginButton.visibility = View.VISIBLE
greeting.visibility = View.INVISIBLE
checkoutSummary.visibility = View.INVISIBLE
paymentmethod.visibility = View.INVISIBLE
payButton.visibility = View.INVISIBLE
payButton.isEnabled = false
}
}
private fun setupPaymentSession () {
// Setup Customer Session
CustomerSession.initCustomerSession(this,FirebaseEphemeralKeyProvider())
// Setup a payment session
paymentSession = PaymentSession(this,PaymentSessionConfig.Builder()
.setShippingInfoRequired(false)
.setShippingMethodsRequired(false)
.setBillingAddressFields(BillingAddressFields.None)
.setShouldShowGooglePay(true)
.build())
paymentSession.init(
object: PaymentSession.PaymentSessionListener {
override fun onPaymentSessionDataChanged(data: PaymentSessionData) {
Log.d("PaymentSession1","11PaymentSession has changed: $data")
Log.d("PaymentSession11","1111 ${data.isPaymentReadyToCharge} <> ${data.paymentMethod}")
if (data.isPaymentReadyToCharge) {
Log.d("PaymentSession2","222Ready to charge");
payButton.isEnabled = true
data.paymentMethod?.let {
Log.d("PaymentSession3","333PaymentMethod $it selected")
paymentmethod.text = "${it.card?.brand} card ends with ${it.card?.last4}"
selectedPaymentMethod = it
}
}
}
override fun onCommunicatingStateChanged(isCommunicating: Boolean) {
Log.d("PaymentSession4","444isCommunicating $isCommunicating")
}
override fun onError(errorCode: Int,errorMessage: String) {
Log.e("PaymentSession5","555onError: $errorCode,$errorMessage")
}
}
)
}
override fun onActivityResult(requestCode: Int,resultCode: Int,data: Intent?) {
super.onActivityResult(requestCode,resultCode,data)
if (requestCode == RC_SIGN_IN) {
val response = IdpResponse.fromResultIntent(data)
if (resultCode == Activity.RESULT_OK) {
currentUser = FirebaseAuth.getInstance().currentUser
Log.d("Login","User ${currentUser?.displayName} has signed in.")
Toast.makeText(applicationContext,"Welcome ${currentUser?.displayName}",Toast.LENGTH_SHORT).show()
showUI()
} else {
Log.d("Login","Signing in failed!")
Toast.makeText(applicationContext,response?.error?.message?:"Sign in failed",Toast.LENGTH_LONG).show()
}
} else {
paymentSession.handlePaymentData(requestCode,data ?: Intent())
}
}
}**
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const { Logging } = require('@google-cloud/logging');
const logging = new Logging({
projectId: process.env.GCLOUD_PROJECT,});
admin.initializeApp();
const stripe = require('stripe')(functions.config().stripe.secret,{
apiVersion: '2020-03-02',});
exports.createEphemeralKey = functions.https.onCall(async (data,context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError(
'failed-precondition','The function must be called while authenticated!'
);
}
const uid = context.auth.uid;
try {
if (!uid) throw new Error('Not authenticated!');
// Get stripe customer id
const customer = (
await admin.firestore().collection('stripe_customers').doc(uid).get()
).data().customer_id;
const key = await stripe.ephemeralKeys.create(
{ customer: customer },{ apiVersion: data.api_version }
);
return key;
} catch (error) {
throw new functions.https.HttpsError('internal',error.message);
}
});
exports.createStripeCustomer = functions.auth.user().onCreate(async (user) => {
const customer = await stripe.customers.create({
email: user.email,metadata: { firebaseUID: user.uid },});
await admin.firestore().collection('stripe_customers').doc(user.uid).set({
customer_id: customer.id,});
return;
});
exports.createStripePayment = functions.firestore
.document('stripe_customers/{userId}/payments/{pushId}')
.onCreate(async (snap,context) => {
const { amount,currency } = snap.data();
try {
// Look up the Stripe customer id.
const customer = (await snap.ref.parent.parent.get()).data().customer_id;
// Create a charge using the pushId as the idempotency key
// to protect against double charges.
const idempotencyKey = context.params.pushId;
const payment = await stripe.paymentIntents.create(
{
amount,currency,customer,},{ idempotencyKey }
);
// If the result is successful,write it back to the database.
await snap.ref.set(payment);
} catch (error) {
// We want to capture errors and render them in a user-friendly way,while
// still logging an exception with StackDriver
console.log(error);
await snap.ref.set({ error: userFacingMessage(error) },{ merge: true });
await reportError(error,{ user: context.params.userId });
}
});
const updatePaymentRecord = async (id) => {
// Retrieve the payment object to make sure we have an up to date status.
const payment = await stripe.paymentIntents.retrieve(id);
const customerId = payment.customer;
// Get customer's doc in Firestore.
const customersSnap = await admin
.firestore()
.collection('stripe_customers')
.where('customer_id','==',customerId)
.get();
if (customersSnap.size !== 1) throw new Error('User not found!');
// Update record in Firestore
const paymentsSnap = await customersSnap.docs[0].ref
.collection('payments')
.where('id',payment.id)
.get();
if (paymentsSnap.size !== 1) throw new Error('Payment not found!');
await paymentsSnap.docs[0].ref.set(payment);
};
exports.cleanupUser = functions.auth.user().onDelete(async (user) => {
const dbRef = admin.firestore().collection('stripe_customers');
const customer = (await dbRef.doc(user.uid).get()).data();
await stripe.customers.del(customer.customer_id);
// Delete the customers payments & payment methods in firestore.
const snapshot = await dbRef
.doc(user.uid)
.collection('payment_methods')
.get();
snapshot.forEach((snap) => snap.ref.delete());
await dbRef.doc(user.uid).delete();
return;
});
exports.handleWebhookEvents = functions.https.onRequest(async (req,resp) => {
const relevantEvents = new Set([
'payment_intent.succeeded','payment_intent.processing','payment_intent.payment_failed','payment_intent.canceled',]);
let event;
try {
event = stripe.webhooks.constructEvent(
req.rawBody,req.headers['stripe-signature'],functions.config().stripe.webhooksecret
);
} catch (error) {
console.error('❗️ Webhook Error: Invalid Secret');
resp.status(401).send('Webhook Error: Invalid Secret');
return;
}
if (relevantEvents.has(event.type)) {
try {
switch (event.type) {
case 'payment_intent.succeeded':
case 'payment_intent.processing':
case 'payment_intent.payment_failed':
case 'payment_intent.canceled':{
const id = event.data.object.id;
await updatePaymentRecord(id);
break;
}
default:
throw new Error('Unhandled relevant event!');
}
} catch (error) {
console.error(
`❗️ Webhook error for [${event.data.object.id}]`,error.message
);
resp.status(400).send('Webhook handler failed. View Function logs.');
return;
}
}
// Return a response to Stripe to acknowledge receipt of the event.
resp.json({ received: true });
});
function reportError(err,context = {}) {
// This is the name of the StackDriver log stream that will receive the log
// entry. This name can be any valid log stream name,but must contain "err"
// in order for the error to be picked up by StackDriver Error Reporting.
const logName = 'errors';
const log = logging.log(logName);
// https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/MonitoredResource
const metadata = {
resource: {
type: 'cloud_function',labels: { function_name: process.env.FUNCTION_NAME },};
// https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorEvent
const errorEvent = {
message: err.stack,serviceContext: {
service: process.env.FUNCTION_NAME,resourceType: 'cloud_function',context: context,};
// Write the error log entry
return new Promise((resolve,reject) => {
log.write(log.entry(metadata,errorEvent),(error) => {
if (error) {
return reject(error);
}
return resolve();
});
});
}
// [END reporterror]
/**
* Sanitize the error message for the user.
*/
function userFacingMessage(error) {
return error.type
? error.message
: 'An error occurred,developers have been alerted';
}
buildTypes.each {
it.buildConfigField 'String','PublishableKey',stripePublishableKey
}
import android.util.Log
import com.google.firebase.functions.FirebaseFunctionsException
import com.google.firebase.functions.ktx.functions
import com.google.firebase.ktx.Firebase
import com.stripe.android.EphemeralKeyProvider
import com.stripe.android.EphemeralKeyUpdateListener
class FirebaseEphemeralKeyProvider: EphemeralKeyProvider {
override fun createEphemeralKey(
apiVersion: String,keyUpdateListener: EphemeralKeyUpdateListener
) {
val data = hashMapOf(
"api_version" to apiVersion
)
// User firebase to call the functions
Firebase.functions
.getHttpsCallable("createEphemeralKey")
.call(data)
.continueWith { task ->
if (!task.isSuccessful) {
val e = task.exception
if (e is FirebaseFunctionsException) {
val code = e.code
val message = e.message
Log.e("EphemeralKey","Ephemeral key provider returns error: $e $code $message")
}
}
val key = task.result?.data.toString()
Log.d("EphemeralKey","Ephemeral key provider returns $key")
keyUpdateListener.onKeyUpdate(key)
}
}
}
import android.app.Application
import com.stripe.android.PaymentConfiguration
class MyApp : Application(){
override fun onCreate() {
super.onCreate()
PaymentConfiguration.init(applicationContext,BuildConfig.PublishableKey)
}
}```
>2020-09-07 09:23:29.753 15967-15967/com.asgd.indigenoussource D/PaymentSession4: 444isCommunicating true
>2020-09-07 09:23:29.754 15967-15967/com.asgd.indigenoussource D/PaymentSession1: 11PaymentSession has changed: PaymentSessionData(isShippingInfoRequired=false,isShippingMethodRequired=false,cartTotal=0,shippingTotal=0,shippingInformation=null,shippingMethod=null,paymentMethod=null,useGooglePay=false)
>2020-09-07 09:23:29.754 15967-15967/com.asgd.indigenoussource D/PaymentSession11: 1111 false <> null
>2020-09-07 09:23:31.636 15967-15967/com.asgd.indigenoussource D/PaymentSession4: 444isCommunicating false
解决方法
从有条纹的人那里得到一些帮助后,它就可以正常工作。我的可发布密钥在gradle中如何进行更改,并且该密钥与设备链接。我必须制造新的模拟设备并重置所有内容
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。