addPaymentMethod Stripe + Firebase Android

如何解决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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-