一、了解Stripe支付
1,最近公司正在做一个国际版APP,涉及到海外支付,调研过Paypal、Skrill、BrainTree、Stripe(可参考海外移动支付方案对比),最终 选择了Stripe支付。Stripe特点如下:
收费规则简单透明,手续费就是收取订单总额的3.4 % + HK$2.35。没有月费、开户费、退款手续费,撤销付款费用手续费HK$85.00
2,Stripe支持135+种货币创建付款(目前不支持中国大陆,只支持中国香港)。
3,Stripe还支持其他付款方式,包括ACH信用转账、ACH借记转账、支付宝、Android Pay、Apple Pay、Bancontact、Bitcoin(比特币)、银行卡(Visa,Mastercard,American Express,Discover,Diners Club,JCB等)、Giropay、iDEAL、SEPA、SOFORT、微信支付等来自全球的热门支付方式。
4, Stripe的开发文档清晰简单,集成友好。提供了IOS、Android的SDK,以及对各种语言的支持。
Android代码:
1,集成SDK
dependencies { // ... // Stripe Android SDK implementation 'com.stripe:stripe-android:20.15.1' }
2,代码
MyApplication代码
package com.example.demo; import android.app.Application; import com.stripe.android.PaymentConfiguration; public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); PaymentConfiguration.init( getApplicationContext(), "pk_test_TYooMQauvdEDq54NiTphI7jx" ); } }
Activity代码:
package com.example.demo; import android.content.res.ColorStateList; import android.graphics.Color; import android.util.Log; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import com.stripe.android.paymentsheet.PaymentSheet; import com.stripe.android.paymentsheet.PaymentSheetResult; import okhttp3.*; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; public class CheckoutActivity extends AppCompatActivity { private static final String TAG = "CheckoutActivity"; private static final String BACKEND_URL = "http://10.0.2.2:4242"; private String paymentIntentClientSecret; private PaymentSheet paymentSheet; private Button payButton; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_checkout); // Hook up the pay button payButton = findViewById(R.id.pay_button); payButton.setOnClickListener(this::onPayClicked); payButton.setEnabled(false); paymentSheet = new PaymentSheet(this, this::onPaymentSheetResult); fetchPaymentIntent(); } private void showAlert(String title, @Nullable String message) { runOnUiThread(() -> { AlertDialog dialog = new AlertDialog.Builder(this) .setTitle(title) .setMessage(message) .setPositiveButton("Ok", null) .create(); dialog.show(); }); } private void showToast(String message) { runOnUiThread(() -> Toast.makeText(this, message, Toast.LENGTH_LONG).show()); } private void fetchPaymentIntent() { final String shoppingCartContent = "{\"items\": [ {\"id\":\"xl-tshirt\"}]}"; final RequestBody requestBody = RequestBody.create( shoppingCartContent, MediaType.get("application/json; charset=utf-8") ); Request request = new Request.Builder() .url(BACKEND_URL + "/create-payment-intent") .post(requestBody) .build(); new OkHttpClient() .newCall(request) .enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { showAlert("Failed to load data", "Error: " + e.toString()); } @Override public void onResponse( @NonNull Call call, @NonNull Response response ) throws IOException { if (!response.isSuccessful()) { showAlert( "Failed to load page", "Error: " + response.toString() ); } else { final JSONObject responseJson = parseResponse(response.body()); paymentIntentClientSecret = responseJson.optString("clientSecret"); runOnUiThread(() -> payButton.setEnabled(true)); Log.i(TAG, "Retrieved PaymentIntent"); } } }); } private JSONObject parseResponse(ResponseBody responseBody) { if (responseBody != null) { try { return new JSONObject(responseBody.string()); } catch (IOException | JSONException e) { Log.e(TAG, "Error parsing response", e); } } return new JSONObject(); } private void onPayClicked(View view) { PaymentSheet.Configuration configuration = new PaymentSheet.Configuration("Example, Inc."); // Present Payment Sheet paymentSheet.presentWithPaymentIntent(paymentIntentClientSecret, configuration); } private void onPaymentSheetResult( final PaymentSheetResult paymentSheetResult ) { if (paymentSheetResult instanceof PaymentSheetResult.Completed) { showToast("Payment complete!"); } else if (paymentSheetResult instanceof PaymentSheetResult.Canceled) { Log.i(TAG, "Payment canceled!"); } else if (paymentSheetResult instanceof PaymentSheetResult.Failed) { Throwable error = ((PaymentSheetResult.Failed) paymentSheetResult).getError(); showAlert("Payment failed", error.getLocalizedMessage()); } } }
xml文件
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".CheckoutActivity" tools:showIn="@layout/activity_checkout"> <Button android:id="@+id/pay_button" android:text="Pay now" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
简不简单,
看效果: