前言 作者:徐庆
团队:坚果派
公众号:“大前端之旅”
专注于分享的技术包括HarmonyOS/OpenHarmony,ArkUI-X,元服务,服务卡片,华为自研语言,团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,欢迎合作。
效果图 : image-20240401165723643 image-20240401165832114 实现方式 我们是通过AkrUi-X和安卓交互 然后在原生安卓里面加入了内购支付结算库的依赖 最后调起的Google 支付 安卓原生内购支付教程
ArkUI端代码 akrui 端我这边只写了一个按钮调用Google内购支付和接收数据
image-20240401170219038 导入平台桥接模块 // 导入平台桥接模块 import bridge from '@arkui-x.bridge' ;
创建平台桥接对象 // 创建平台桥接对象 private bridgeImpl = bridge.createBridge('Bridge' );
// 发送数据到Android侧,并通过状态变量,将Android侧的响应数据显示在页面上 this.nativeResponse = await this.bridgeImpl.sendMessage('Hello ArkUI-X!' );
接收回传回来的数据 aboutToAppear () { this.getHelloArkUI(); } getHelloArkUI () { // 调用Android侧方法 this.bridgeImpl.callMethod('getHelloArkUI' ).then ((result: string) => { // 通过状态变量,将Android侧方法的返回值显示在页面上 this.helloArkUI = result; });
完整代码 // 导入平台桥接模块 import bridge from '@arkui-x.bridge' ; @Entry @Component struct Index { // 创建平台桥接对象 private bridgeImpl = bridge.createBridge('Bridge' ); @State helloArkUI: string = '' ; @State nativeResponse: string = '' ; aboutToAppear () { this.getHelloArkUI(); } getHelloArkUI () { // 调用Android侧方法 // this.bridgeImpl.callMethod('getHelloArkUI' ).then ((result: string) => { // // 通过状态变量,将Android侧方法的返回值显示在页面上 // this.helloArkUI = result; // }); /* this.bridgeImpl?.callMethod('getHelloArkUI' ).then ((data)=>{ });*/ // let resultPromise=this.bridgeImpl.callMethod('getHelloArkUI' ):resultPromise.then((data)=>{ // // // // }) } build () { Row () { Column () { Text(this.helloArkUI) .fontSize(15) .margin(10) Button('点击Google支付' ) .fontSize(15) .margin(10) .onClick(async () => { // 发送数据到Android侧,并通过状态变量,将Android侧的响应数据显示在页面上 await this.bridgeImpl.sendMessage('Hello ArkUI-X!' ); }) Text('Response from Native: ' + this.nativeResponse) .fontSize(15) .margin(10) } .width('100%' ) } .height('100%' ) } }
安卓部分 我们编译项目 需要导入arkui-x编译之后产生的安卓原生宿主工程
image-20240401170755439 官方文档地址 Google结算库
需要的依赖 def billing_version = "6.0.0" implementation "com.android.billingclient:billing:$billing_version"
image-20240401170856828 akrui-x 和原生安卓通信交互 引用平台桥接模块 package com.example.helloworld; /** * 作者:xuqing * 时间:2024年04月01日 15:27:31 * 邮箱:1693891473@qq.com * 说明: */ import android.app.Activity; import android.content.Context; import android.util.Log; // 引用平台桥接模块 import ohos.ace.adapter.capability.bridge.BridgePlugin; import ohos.ace.adapter.capability.bridge.IMessageListener; public class Bridge extends BridgePlugin implements IMessageListener { private static final String TAG = "Bridge" ; private Context context; public Bridge(Context context, String name, int id) { super(context, name, id); this.context=context; setMessageListener(this); } // Android侧方法,供ArkUI侧调用 public String getHelloArkUI () { return "Hello ArkUI!" ; } // 注册回调,接收ArkUI侧发来的数据 @Override public Object onMessage(Object object) { // new EntryEntryAbilityActivity(). initgooglePlay(); GooglePay.getInstance().toGooglePay((Activity) context,"com.testgame.099" ); Log.e(TAG, "onMessage: " +object.toString() ); return "java onMessage success" ; } @Override public void onMessageResponse(Object object) { } }
内购支付初始化 public void initgooglePlay(Activity context) { billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases() .build(); if (billingClient!=null){ billingClient.startConnection(new BillingClientStateListener () { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { } } @Override public void onBillingServiceDisconnected () { } }); } }
调用起内购支付 public void toGooglePay(Activity context,String productId){ // String productId ="xxxx" ; List<QueryProductDetailsParams.Product> productList= new ArrayList<>(); productList.add(QueryProductDetailsParams.Product.newBuilder() .setProductId(productId) .setProductType(BillingClient.ProductType.INAPP) .build()); QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder(). setProductList(productList) .build(); if (billingClient!=null){ billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener () { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { if (productDetailsList!=null&&productDetailsList.size()>0){ ProductDetails productDetails=productDetailsList.get(0); List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList= new ArrayList<>(); productDetailsParamsList.add(BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .build()); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); billingClient.launchBillingFlow((Activity) context, billingFlowParams); }else { Toast.makeText(context,"商品ID无效" ,Toast.LENGTH_SHORT).show(); } } } ); } }
我们在arkui-x调用安卓原生的回调方法里面去调用我们的 toGooglePay 传入我们的商品ID 即可
private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener () { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { handlePurchase(purchase); Log.e(TAG, "getPurchaseToken: " + purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); } } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { } else { } } };
我们拿到回调里面的 getPurchaseToken getSignature getSignature 信息之后可以去自己服务端进行验签 如果验签成功了才算是真正的成功支付成功 然后再进行消耗
public void handlePurchase(final Purchase purchase) { ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener () { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { Log.e(TAG, "getPurchaseToken: " + purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); } } }; if (billingClient!=null){ billingClient.consumeAsync(consumeParams, listener); } }
public void queryPurchasesAsync(Activity context){ if (billingClient!=null){ if (!billingClient.isReady()){ Toast.makeText(context,"BillingClient is not ready" ,Toast.LENGTH_SHORT).show(); } billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build(), new PurchasesResponseListener () { public void onQueryPurchasesResponse( BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK){ if (purchases!=null&&purchases.size()>0){ for (Purchase purchase:purchases){ handlePurchase(purchase); } } } } } ); } }
请再 onResume 声明周期方法里面调用 @Override protected void onResume () { super.onResume(); GooglePay.getInstance().queryPurchasesAsync(EntryEntryAbilityActivity.this); }
完整Android端代码 EntryEntryAbilityActivity 端代码
package com.example.helloworld; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.Log; import com.android.billingclient.api.BillingClient; import ohos.stage.ability.adapter.StageActivity; /** * Example ace activity class, which will load ArkUI-X ability instance. * StageActivity is provided by ArkUI-X * @see <a href= * "https:///arkui-crossplatform/doc/blob/master/contribute/tutorial/how-to-build-Android-app.md" > * to build android library</a> */ public class EntryEntryAbilityActivity extends StageActivity { private static final String TAG = "MainActivity" ; private Context context=EntryEntryAbilityActivity.this; private BillingClient billingClient; @Override protected void onCreate(Bundle savedInstanceState) { Log.e("HiHelloWorld" , "EntryEntryAbilityActivity" ); new Bridge(this, "Bridge" , getInstanceId()); //setInstanceName("com.example.helloworld:entry:EntryAbility:" ); setInstanceName("com.example.helloworld:entry:EntryAbility:" ); super.onCreate(savedInstanceState); GooglePay.getInstance().initgooglePlay(EntryEntryAbilityActivity.this); } @Override protected void onResume () { super.onResume(); GooglePay.getInstance().queryPurchasesAsync(EntryEntryAbilityActivity.this); } @Override public void onStop () { super.onStop(); } @Override protected void onPause () { super.onPause(); } }
googlepay 工具类代码 package com.example.helloworld; import android.app.Activity; import android.content.Context; import android.util.Log; import android.widget.Toast; import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClientStateListener; import com.android.billingclient.api.BillingFlowParams; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.ConsumeParams; import com.android.billingclient.api.ConsumeResponseListener; import com.android.billingclient.api.ProductDetails; import com.android.billingclient.api.ProductDetailsResponseListener; import com.android.billingclient.api.Purchase; import com.android.billingclient.api.PurchasesResponseListener; import com.android.billingclient.api.PurchasesUpdatedListener; import com.android.billingclient.api.QueryProductDetailsParams; import com.android.billingclient.api.QueryPurchasesParams; import java.util.ArrayList; import java.util.List; /** * 作者:xuqing * 时间:2024年04月01日 16:20:30 * 邮箱:1693891473@qq.com * 说明: */ public class GooglePay { private static final String TAG = "GooglePay" ; private BillingClient billingClient; private static GooglePay instance=null; private GooglePay () { } public static GooglePay getInstance (){ if (instance==null){ synchronized (GooglePay.class){ if (instance==null){ instance=new GooglePay(); } } } return instance; } private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener () { @Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { handlePurchase(purchase); Log.e(TAG, "getPurchaseToken: " + purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); } } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { } else { } } }; public void handlePurchase(final Purchase purchase) { ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); ConsumeResponseListener listener = new ConsumeResponseListener () { @Override public void onConsumeResponse(BillingResult billingResult, String purchaseToken) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { Log.e(TAG, "getPurchaseToken: " + purchase.getPurchaseToken() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); Log.e(TAG, "getSignature: " + purchase.getSignature() ); } } }; if (billingClient!=null){ billingClient.consumeAsync(consumeParams, listener); } } public void initgooglePlay(Activity context) { billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) .enablePendingPurchases() .build(); if (billingClient!=null){ billingClient.startConnection(new BillingClientStateListener () { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { } } @Override public void onBillingServiceDisconnected () { } }); } } public void toGooglePay(Activity context,String productId){ // String productId ="xxxx" ; List<QueryProductDetailsParams.Product> productList= new ArrayList<>(); productList.add(QueryProductDetailsParams.Product.newBuilder() .setProductId(productId) .setProductType(BillingClient.ProductType.INAPP) .build()); QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder(). setProductList(productList) .build(); if (billingClient!=null){ billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener () { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { if (productDetailsList!=null&&productDetailsList.size()>0){ ProductDetails productDetails=productDetailsList.get(0); List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList= new ArrayList<>(); productDetailsParamsList.add(BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .build()); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); billingClient.launchBillingFlow((Activity) context, billingFlowParams); }else { Toast.makeText(context,"商品ID无效" ,Toast.LENGTH_SHORT).show(); } } } ); } } public void queryPurchasesAsync(Activity context){ if (billingClient!=null){ if (!billingClient.isReady()){ Toast.makeText(context,"BillingClient is not ready" ,Toast.LENGTH_SHORT).show(); } billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build(), new PurchasesResponseListener () { public void onQueryPurchasesResponse( BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK){ if (purchases!=null&&purchases.size()>0){ for (Purchase purchase:purchases){ handlePurchase(purchase); } } } } } ); } } }
最后总结: