最近老大提出了一个需求,在应用里面加一个内购。由于之前没做过这块,所以百度一番。网上都是讲的使用一大堆的utils、还要加一个aidl文件。感觉挺麻烦的。最终让我找到了:com.android.billingclient:billing:1.0 。使用该依赖,解决了一大堆的utils。

好了,开始介绍下使用步骤:

一、代码部分

①、在AndroidManifest.xml中添加内购权限。

<uses-permission android:name="com.android.vending.BILLING" />

这个是必须的。

②、加入依赖。

compile 'com.android.billingclient:billing:1.0'
//如果用到isGooglePlayServicesAvailable方法需要导入这个包,这个方法也可以去掉。implementation 'com.google.android.gms:play-services-basement:11.8.0'

③、代码封装:

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.support.annotation.Nullable;
import android.util.Log;import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.ConsumeResponseListener;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** 对isGooglePlayServicesAvailable方法进行了说明,因为这个方法是要导入一个包才能使用的。* api "com.google.android.gms:play-services-location:11.8.0"也可以不用*/@SuppressWarnings("ALL")
public class GoogleBillingUtil {private static final String TAG = "```GoogleBillingUtil";private static final boolean IS_DEBUG = true;
//googleplay应用内商品栏,添加商品后得到private String[] inAppSKUS = new String[]{"","",""};//内购ID,必填private String[] subsSKUS = new String[]{"","",""};//订阅ID,必填public static final String BILLING_TYPE_INAPP = BillingClient.SkuType.INAPP;//内购public static final String BILLING_TYPE_SUBS = BillingClient.SkuType.SUBS;//订阅private static BillingClient mBillingClient;private static BillingClient.Builder builder ;private static OnPurchaseFinishedListener mOnPurchaseFinishedListener;private static OnStartSetupFinishedListener mOnStartSetupFinishedListener ;private static OnQueryFinishedListener mOnQueryFinishedListener;private boolean isAutoConsumeAsync = true;//是否在购买成功后自动消耗商品private static final GoogleBillingUtil mGoogleBillingUtil = new GoogleBillingUtil() ;private GoogleBillingUtil(){}public static GoogleBillingUtil getInstance(){cleanListener();return mGoogleBillingUtil;}public GoogleBillingUtil build(Context context){if(mBillingClient==null){synchronized (mGoogleBillingUtil){if(mBillingClient==null){if(isGooglePlayServicesAvailable(context)){builder = BillingClient.newBuilder(context);mBillingClient = builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener()).build();}else{if(IS_DEBUG){log("警告:GooglePlay服务处于不可用状态,请检查");}if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupError();}}}else{builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener());}}}else{builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener());}synchronized (mGoogleBillingUtil){if(mGoogleBillingUtil.startConnection()){mGoogleBillingUtil.queryInventoryInApp();mGoogleBillingUtil.queryInventorySubs();mGoogleBillingUtil.queryPurchasesInApp();}}return mGoogleBillingUtil;}public boolean startConnection(){if(mBillingClient==null){log("初始化失败:mBillingClient==null");return false;}if(!mBillingClient.isReady()){mBillingClient.startConnection(new BillingClientStateListener() {@Overridepublic void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode) {if (billingResponseCode == BillingClient.BillingResponse.OK) {queryInventoryInApp();queryInventorySubs();queryPurchasesInApp();if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupSuccess();}}else{log("初始化失败:onSetupFail:code="+billingResponseCode);if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupFail(billingResponseCode);}}}@Overridepublic void onBillingServiceDisconnected() {if(mOnStartSetupFinishedListener!=null){mOnStartSetupFinishedListener.onSetupError();}log("初始化失败:onBillingServiceDisconnected");}});return false;}else{return true;}}/*** Google购买商品回调接口(订阅和内购都走这个接口)*/private class MyPurchasesUpdatedListener implements PurchasesUpdatedListener{@Overridepublic void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> list) {if(mOnPurchaseFinishedListener==null){if(IS_DEBUG){log("警告:接收到购买回调,但购买商品接口为Null,请设置购买接口。eg:setOnPurchaseFinishedListener()");}return ;}if(responseCode== BillingClient.BillingResponse.OK&&list!=null){if(isAutoConsumeAsync){//消耗商品for(Purchase purchase:list){String sku = purchase.getSku();if(sku!=null){String skuType = getSkuType(sku);if(skuType!=null){if(skuType.equals(BillingClient.SkuType.INAPP)){consumeAsync(purchase.getPurchaseToken());}}}}}mOnPurchaseFinishedListener.onPurchaseSuccess(list);}else{mOnPurchaseFinishedListener.onPurchaseFail(responseCode);}}}/*** 查询内购商品信息*/public void queryInventoryInApp(){queryInventory(BillingClient.SkuType.INAPP);}/*** 查询订阅商品信息*/public void queryInventorySubs(){queryInventory(BillingClient.SkuType.SUBS);}private void queryInventory(final String skuType) {Runnable runnable = new Runnable() {@Overridepublic void run() {if (mBillingClient == null){if(mOnQueryFinishedListener!=null){mOnQueryFinishedListener.onQueryError();}return ;}ArrayList<String> skuList = new ArrayList<>();if(skuType.equals(BillingClient.SkuType.INAPP)){Collections.addAll(skuList, inAppSKUS);}else if(skuType.equals(BillingClient.SkuType.SUBS)){Collections.addAll(skuList, subsSKUS);}SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();params.setSkusList(skuList).setType(skuType);mBillingClient.querySkuDetailsAsync(params.build(),new MySkuDetailsResponseListener(mOnQueryFinishedListener,skuType));}};executeServiceRequest(runnable);}/*** Google查询商品信息回调接口*/private class MySkuDetailsResponseListener implements SkuDetailsResponseListener{private OnQueryFinishedListener mOnQueryFinishedListener ;private String skuType ;public MySkuDetailsResponseListener(OnQueryFinishedListener onQueryFinishedListener,String skuType) {mOnQueryFinishedListener = onQueryFinishedListener;this.skuType = skuType;}@Overridepublic void onSkuDetailsResponse(int responseCode , List<SkuDetails> list) {if(mOnQueryFinishedListener==null){if(IS_DEBUG) {log("警告:接收到查询商品回调,但查询商品接口为Null,请设置购买接口。eg:setOnQueryFinishedListener()");}return ;}if(responseCode== BillingClient.BillingResponse.OK&&list!=null){mOnQueryFinishedListener.onQuerySuccess(skuType,list);}else{mOnQueryFinishedListener.onQueryFail(responseCode);}}}/*** 发起内购* @param skuId* @return*/public void purchaseInApp(Activity activity,String skuId){purchase(activity,skuId, BillingClient.SkuType.INAPP);}/*** 发起订阅* @param skuId* @return*/public void purchaseSubs(Activity activity,String skuId){purchase(activity,skuId, BillingClient.SkuType.SUBS);}private void purchase(Activity activity,final String skuId,final String skuType){if(mBillingClient==null){if(mOnPurchaseFinishedListener!=null){mOnPurchaseFinishedListener.onPurchaseError();}return ;}if(startConnection()){BillingFlowParams flowParams = BillingFlowParams.newBuilder().setSku(skuId).setType(skuType).build();mBillingClient.launchBillingFlow(activity,flowParams);}else{if(mOnPurchaseFinishedListener!=null){mOnPurchaseFinishedListener.onPurchaseError();}}}/*** 消耗商品* @param purchaseToken*/public void consumeAsync(String purchaseToken){if(mBillingClient==null){return ;}mBillingClient.consumeAsync(purchaseToken, new MyConsumeResponseListener());}/*** Googlg消耗商品回调*/private class MyConsumeResponseListener implements ConsumeResponseListener{@Overridepublic void onConsumeResponse(int responseCode, String s) {if (responseCode == BillingClient.BillingResponse.OK) {}}}/*** 获取已经内购的商品* @return*/public List<Purchase> queryPurchasesInApp(){return queryPurchases(BillingClient.SkuType.INAPP);}/*** 获取已经订阅的商品* @return*/public List<Purchase> queryPurchasesSubs(){return queryPurchases(BillingClient.SkuType.SUBS);}private List<Purchase> queryPurchases(String skuType){if(mBillingClient==null){return null;}if(!mBillingClient.isReady()){startConnection();}else{Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(skuType);if(purchasesResult!=null){if(purchasesResult.getResponseCode()== BillingClient.BillingResponse.OK){List<Purchase> purchaseList =  purchasesResult.getPurchasesList();if(isAutoConsumeAsync){if(purchaseList!=null){for(Purchase purchase:purchaseList){if(skuType.equals(BillingClient.SkuType.INAPP)){consumeAsync(purchase.getPurchaseToken());}}}}return purchaseList;}}}return null;}/*** 获取有效订阅的数量* @return -1查询失败,0没有有效订阅,>0具有有效的订阅*/public int getPurchasesSizeSubs(){List<Purchase> list = queryPurchasesSubs();if(list!=null){return list.size();}return -1;}/*** 通过sku获取订阅商品序号* @param sku* @return*/public int getSubsPositionBySku(String sku){return getPositionBySku(sku, BillingClient.SkuType.SUBS);}/*** 通过sku获取内购商品序号* @param sku* @return 成功返回需要 失败返回-1*/public int getInAppPositionBySku(String sku){return getPositionBySku(sku, BillingClient.SkuType.INAPP);}private int getPositionBySku(String sku,String skuType){if(skuType.equals(BillingClient.SkuType.INAPP)){int i = 0;for(String s:inAppSKUS){if(s.equals(sku)){return i;}i++;}}else if(skuType.equals(BillingClient.SkuType.SUBS)){int i = 0;for(String s:subsSKUS){if(s.equals(sku)){return i;}i++;}}return -1;}private void executeServiceRequest(final Runnable runnable){if(startConnection()){runnable.run();}}/*** 通过序号获取订阅sku* @param position* @return*/public String getSubsSkuByPosition(int position){if(position>=0&&position<subsSKUS.length){return subsSKUS[position];}else {return null;}}/*** 通过序号获取内购sku* @param position* @return*/public String getInAppSkuByPosition(int position){if(position>=0&&position<inAppSKUS.length){return inAppSKUS[position];}else{return null;}}/*** 通过sku获取商品类型(订阅获取内购)* @param sku* @return inapp内购,subs订阅*/private String getSkuType(String sku){if(Arrays.asList(inAppSKUS).contains(sku)){return BillingClient.SkuType.INAPP;}else if(Arrays.asList(subsSKUS).contains(sku)){return BillingClient.SkuType.SUBS;}return null;}/*** 检测GooglePlay服务是否可用(需要导入包api "com.google.android.gms:play-services-location:11.8.0",也可以不检查,跳过这个代码)* @param context* @return*/public static boolean isGooglePlayServicesAvailable(Context context){GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();if(googleApiAvailability!=null){int resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context);return resultCode == ConnectionResult.SUCCESS;}return false;//return true;//不检查直接跳过}public GoogleBillingUtil setOnQueryFinishedListener(OnQueryFinishedListener onQueryFinishedListener) {mOnQueryFinishedListener = onQueryFinishedListener;return mGoogleBillingUtil;}public GoogleBillingUtil setOnPurchaseFinishedListener(OnPurchaseFinishedListener onPurchaseFinishedListener) {mOnPurchaseFinishedListener = onPurchaseFinishedListener;return mGoogleBillingUtil;}public OnStartSetupFinishedListener getOnStartSetupFinishedListener() {return mOnStartSetupFinishedListener;}public GoogleBillingUtil setOnStartSetupFinishedListener(OnStartSetupFinishedListener onStartSetupFinishedListener) {mOnStartSetupFinishedListener = onStartSetupFinishedListener;return mGoogleBillingUtil;}/***  本工具查询回调接口*/public interface OnQueryFinishedListener{//Inapp和sub都走这个接口查询的时候一定要判断skuTypepublic void onQuerySuccess(String skuType, List<SkuDetails> list);public void onQueryFail(int responseCode);public void onQueryError();}/*** 本工具购买回调接口(内购与订阅都走这接口)*/public interface OnPurchaseFinishedListener{public void onPurchaseSuccess(List<Purchase> list);public void onPurchaseFail(int responseCode);public void onPurchaseError();}/*** google服务启动接口*/public interface OnStartSetupFinishedListener{public void onSetupSuccess();public void onSetupFail(int responseCode);public void onSetupError();}public boolean isReady() {return mBillingClient!=null&&mBillingClient.isReady();}public boolean isAutoConsumeAsync(){return isAutoConsumeAsync;}public void setIsAutoConsumeAsync(boolean isAutoConsumeAsync){this.isAutoConsumeAsync= isAutoConsumeAsync;}/*** 清除所有监听器,防止内存泄漏* 如果有多个页面使用了支付,需要确保上个页面的cleanListener在下一个页面的GoogleBillingUtil.getInstance()前使用。* 所以不建议放在onDestory里调用*/public static void cleanListener(){mOnPurchaseFinishedListener = null;mOnQueryFinishedListener = null;mOnStartSetupFinishedListener = null;if(builder!=null){builder.setListener(null);}}/*** 断开连接google服务* 注意!!!一般情况不建议调用该方法,让google保留连接是最好的选择。*/public static void endConnection(){//注意!!!一般情况不建议调用该方法,让google保留连接是最好的选择。if(mBillingClient!=null){if(mBillingClient.isReady()){mBillingClient.endConnection();mBillingClient = null;}}}private static void log(String msg){if(IS_DEBUG){Log.e(TAG,msg);}}/*** 是否支持内购*/public  boolean isIabServiceAvailable(Context context){final PackageManager packageManager = context.getPackageManager();List<ResolveInfo> list = packageManager.queryIntentServices(getBindServiceIntent(), 0);return list != null && list.size() > 0;}private  Intent getBindServiceIntent(){Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");intent.setPackage("com.android.vending");return intent;}
}

代码可以直接拿去用的,不需要填入key值。

④、代码示例:

private GoogleBillingUtil googleBillingUtil = null;
private MyOnPurchaseFinishedListener mOnPurchaseFinishedListener = new MyOnPurchaseFinishedListener();//购买回调接口
private MyOnQueryFinishedListener mOnQueryFinishedListener = new MyOnQueryFinishedListener();//查询回调接口
private MyOnStartSetupFinishedListener mOnStartSetupFinishedListener = new OnStartSetupFinishedListener();//启动结果回调接口

4.1:创建示例,需要在build之前设置回调接口,接口可以选择性设置

@Override
protected void onStart() {super.onStart();/*建议放在onStart里面初始化,因为你可能在别的页面与谷歌服务断开了连接或者设置了接口,所以当一个页面打开的时候,你应该重新检测连接是否正常(如果断开则重新连接)并重新设置接口*/googleBillingUtil = GoogleBillingUtil.getInstance().setOnPurchaseFinishedListener(mOnPurchaseFinishedListener).setOnQueryFinishedListener(mOnQueryFinishedListener).setOnStartSetupFinishedListener(mOnStartSetupFinishedListener).build();
}

4.2:发起内购或者订阅

public void queryInventoryInApp() 查询内购商品信息列表
public void queryInventorySubs() 查询订阅商品信息列表
public void purchaseInApp(Activity activity,String skuId) 发起内购
public void purchaseSubs(Activity activity,String skuId) 发起订阅

4.3:清除监听

//如果下个页面或者上个页面没有使用到googleBuillingUtil.getInstance(),那么就需要在finish或者startActivity之前调用cleanListener()方法,来清除接口。
//可以尝试这样
@Overridepublic void onBackPressed() {GoogleBillingUtil.cleanListener();super.onBackPressed();}
//返回键点击
public void onBackClick(){GoogleBillingUtil.cleanListener();this.finish();}//如果只使用一次googleBuillingUtil,可以选择使用endConnection()方法断开google服务的连接,下次使用重新连接。

4.4:接口说明

//查询商品信息回调接口
private class MyOnQueryFinishedListener implements GoogleBillingUtil.OnQueryFinishedListener
{@Overridepublic void onQuerySuccess(String skuType,List<SkuDetails> list) {//查询成功,返回商品列表,//skuDetails.getPrice()获得价格(文本)//skuDetails.getType()获得类型 sub或者inapp,因为sub和inapp的查询结果都走这里,所以需要判断。//googleBillingUtil.getSubsPositionBySku(skuDetails.getSku())获得当前subs sku的序号//googleBillingUtil.getInAppPositionBySku(skuDetails.getSku())获得当前inapp suk的序号}@Overridepublic void onQueryFail(int responseCode) {//查询失败}@Overridepublic void onQueryError() {//查询错误}
}
//服务初始化结果回调接口
private class MyOnStartSetupFinishedListener implements GoogleBillingUtil.OnStartSetupFinishedListener
{
//...;
}
//购买商品回调接口
private class MyOnPurchaseFinishedListener implements GoogleBillingUtil.OnPurchaseFinishedListener
{@Overridepublic void onPurchaseSuccess(List<Purchase> list) {//内购或者订阅成功,可以通过purchase.getSku()获取suk进而来判断是哪个商品}@Overridepublic void onPurchaseFail(int responseCode) {}@Overridepublic void onPurchError() {}
}

4.5:api说明:

//初始化
1、public static GoogleBillingUtil getInstance() 获取单实例
2、public GoogleBillingUtil build() 创建内购实例,连接谷歌支付服务(如果未创建、未连接),并查询商品信息列表。如果默认自动消耗已内购但未被消耗的商品,可以通过设置isAutoConsumeAsync改变。
3、public void startConnection() 连接谷歌支付服务(一般情况下不需要手动调用,build的时候已经调用了)//查询、购买与消耗
4、public void queryInventoryInApp() 查询内购商品信息列表
5、public void queryInventorySubs() 查询订阅商品信息列表
6、public void purchaseInApp(Activity activity,String skuId) 发起内购
7、public void purchaseSubs(Activity activity,String skuId) 发起订阅
8、public void consumeAsync(String purchaseToken) 消耗商品(一般情况下不需要手动调用,内购的时候自动调用了)//购买历史、有效订阅数
9、public List<Purchase> queryPurchasesInApp() 获取已经内购的商品列表
10、public List<Purchase> queryPurchasesSubs() 获取已经订阅的商品列表
11、public int getPurchasesSizeSubs() 获取有效订阅的数量(-1查询失败,0没有有效订阅,>0具有有效的订阅)//便捷工具
12、public int getSubsPositionBySku(String sku) 通过sku获取订阅商品序号
13、public int getInAppPositionBySku(String sku) 通过sku获取内购商品序号
14、public String getSubsSkuByPosition(int position) 通过序号获取订阅sku
15、public String getInAppSkuByPosition(int position) 通过序号获取内购sku
16、private String getSkuType(String sku) 通过sku获取商品类型(订阅获取内购)inapp内购,subs订阅//接口设置
17、public GoogleBillingUtil setOnPurchaseFinishedListener(OnPurchaseFinishedListener onPurchaseFinishedListener) 购买回调接口
18、public GoogleBillingUtil setOnQueryFinishedListener(OnQueryFinishedListener onQueryFinishedListener) 商品信息查询接口
19、public GoogleBillingUtil setOnStartSetupFinishedListener(OnStartSetupFinishedListener onStartSetupFinishedListener) 服务初始化结果回调接口 //其他、内存
20、public void setIsAutoConsumeAsync(boolean isAutoConsumeAsync) 设置是否自动消耗商品
21、public static void cleanListener() 清除所有监听器,避免内存泄漏,回调错乱等问题。
22、public static void endConnection() 断开连接google服务(一般情况不建议调用该方法,让google保留连接是最好的选择。)

二、googleplay操作部分:

当你把代码添加完成后,可以在代码中添加一个skuid :(由字母和数字组成,例如weather_54).private String[] inAppSKUS = new String[]{"weather_54","",""},这个要与googlePlay应用内商品栏的添加商品一栏对应。然后打包apk.

①、翻墙上传应用,应用上传部分这里不做详细讲解。可以先上传一个内部测试版本。内部测试版本支付不会扣除金额。如下图所示:

我这里上传的是alpha测试版本,可以添加测试人员。当完成apk上传之后,会生成一个测试版本的googleplay下载地址。

②、应用内商品

当你的应用存在需要google登录或者其他使用到签名的位置的话,记住:千万不要选择应用签名!千万不要选择应用签名!千万不要选择应用签名!。它会覆盖你的签名。而且不可逆操作。

需要你填写一些信息,例如银行卡之类的。这里公司已经填好了。

③、添加商品:

还记得那个skuid么,对。就是这个Id名称。

④、开始填写定价内容:

红框里面的内容可以更改。

好了。保存更改后。就可以进行测试了。如果你的代码以及googleplay应用都ok的话。点击支付,就可以看到如下图所示:

文章就到这里了。有疑问随时可以@我~~~~thanks

Google内购--封装版相关推荐

  1. google内购-订阅模式

    1.订单有变化接收google推送的接口,据此可以实现续订订单 /*** 接收google推送接口* @param body* @param request* @param response* @re ...

  2. Python Google内购服务端验证

    Google内购完成后,服务端需要校验订单的状态是否正确(是否已经成功付款). 一.申请认证 参考https://developers.google.cn/android-publisher/gett ...

  3. Google 内购总结

    Google 内购坑之总结 最近项目中增加了 Google 内购的内容,接入并不难,在这里总结下接入过程中的细节和坑的地方. 内购接入过程 如何接入官方的教程写的很详细(传送门),并且官方也提供了一个 ...

  4. 【Unity】Google内购

    目录 一.创建空安卓库工程 二.Unity配置 三.注意事项 版本更新注意事项 服务器相关(相关文章如下) 支付相关错误码 https://developer.android.com/google/p ...

  5. google内购In-App Billing

    本帖地址:http://blog.csdn.net/jinjian2009/article/details/9140891 这周做了google的内购,没搞过google的内购还是觉得比较繁琐的 go ...

  6. Google 内购 - Android

    1. 添加依赖 implementation "com.android.billingclient:billing:5.0.0" 2.支付相关的代码 /*** 连接**/publi ...

  7. java集成Google Pay内购

    挺简单的直接上代码: api入参 @Data @ApiModel("google支付表单信息") public class GooglePayForm {/*** 包名*/@Api ...

  8. Android逆向笔记-某水果大作战内购破解思路

    思路一: 在游戏中,我们点下支付或购买,弹出一个框,我们点返回,就购买成功: 将成功转Unicode进行搜索后: 定位在此,发现payResultSuccess()为购买成功,payResultCan ...

  9. [最新版]火柴人联盟v1.14.1去签名验证去广告Android内购破解(附smali篇幅有点长啊)

    授人以鱼不如授人以渔,谁将授吾以渔? --by B.S. {:1_892:} 废话不多说了.先上图,分析修改说明随后附上.  注: 文章排版是用的论坛Markdown编辑的(因我的博客是基于markd ...

最新文章

  1. OpenCV实现RGB颜色空间和HSI颜色空间的相互转换
  2. IOS图像拉伸解决方案
  3. 【李宏毅2020 ML/DL】P82 Generative Adversarial Network | Improving Sequence Generation by GAN
  4. 无法找到 Adobe PDF资源文件。“Acrobat PDFMaker“您必须具有”管理员”权限方可安装这些文件...错误怎么解决
  5. 自然语言处理与企业对话系统设计
  6. c# mvc ajax txt auto,ASP.Net MVC和复制div中的自我AJAX更新局部视图/控制器
  7. 坚果云和亿方云该如何选?
  8. 2022茶艺师(中级)考试题模拟考试题库及模拟考试
  9. 2018版ISTQB FL基础级大纲全解析
  10. 山东大学2021算法期末
  11. 编译原理:LL(1)语法分析器的实现(内含代码详细注释)
  12. Linux内核设计与实现 第19章 可移植性
  13. 联想hx系列服务器,联想ThinkAgile HX系列 融合
  14. ENSP华为路由器FTP服务器实验
  15. docker_相关操作
  16. c语言-大小顺序排列
  17. 二进制形式配置k8s集群(二)-生成证书
  18. Tapestry 教程(六)使用BeanEditForm来创建用户表单
  19. thinkphp6 短信宝/腾讯云发送手机号验证码
  20. 关于自己的转正述职报告

热门文章

  1. python断点调试:pdb基本用法
  2. iPhonexs文件连接服务器,iphone XS怎么刷公交?iphone XS乘坐公交方法
  3. chatgpt中文玩法提示词
  4. 牛客网 Java 工程师能力评估 20 题 - 详解
  5. c51单片机秒表程序c语言,用51单片机制作一个秒表的详细过程(教程有程序)
  6. python西塔怎么打出来_希腊字母怎么读_希腊字母怎么打出来
  7. 灰度DeFi入门报告:跨越边界的网络银行
  8. 人脸识别技术 介绍,现况以及应用
  9. 使用计算机粘贴板的步骤,如何打开电脑剪贴板图文教程
  10. 解释一下什么是网盘与云盘