前言

团队介绍

作者:徐庆

团队:坚果派 公众号:“大前端之旅” 润开鸿生态技术专家,华为HDE,CSDN博客专家,CSDN超级个体,CSDN特邀嘉宾,InfoQ签约作者,OpenHarmony布道师,电子发烧友专家博客,51CTO博客专家,擅长HarmonyOS/OpenHarmony应用开发、熟悉服务卡片开发。欢迎合作。

效果图 :

img

img

实现方式

我们是通过AkrUi-X和安卓交互 然后在原生安卓里面加入了内购支付结算库的依赖 最后调起的Google 支付 安卓原生内购支付教程

ArkUI端代码

akrui 端我这边只写了一个按钮调用Google内购支付和接收数据

img

导入平台桥接模块

// 导入平台桥接模块
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编译之后产生的安卓原生宿主工程

img

官方文档地址

Google结算库

需要的依赖

def billing_version = "6.0.0" implementation "com.android.billingclient:billing:$billing_version"

img

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://gitee.com/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);
                                    }
                                }
                            }
                        }
                    }
            );
        }
    }

}

最后总结:

鸿蒙arkui-x才是刚起步希望有更多开发能加入进来一起共同建设完善好生态。也希望国产系统和框架越来越好 最后呢 希望我都文章能帮助到各位同学工作和学习 如果你觉得文章还不错麻烦给我三连 关注点赞和转发 谢谢

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐