AndroidManifest.xml文件信息配置如下:
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ConsumptionActivity"></activity>
</application>
<!--取消一直检查跟新华为HMS-->
<queries>
<intent>
<action android:name="com.huawei.hms.core.aidlservice" />
</intent>
</queries>
主模块下面的gradle如下:
plugins {
id 'com.android.application'
}
android { compileSdkVersion 30 buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.qf.myqfpay"
minSdkVersion 17 //不能低于17
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
config {
storeFile file('D:\\worker\\MyQfpay\\qf.jks')
storePassword '123456'
keyPassword '123456'
keyAlias 'qf'
}
}
buildTypes {
debug {
signingConfig signingConfigs.config
}
release {
signingConfig signingConfigs.config
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.huawei.hms:iap:5.0.1.300'
} apply plugin: 'com.huawei.agconnect'
工程模块下面的build代码如下: // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() maven { url 'developer.huawei.com/repo/' } } dependencies { classpath "com.android.tools.build:gradle:4.1.1"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
}
}
allprojects { repositories { google() jcenter() maven { url 'developer.huawei.com/repo/' } } }
task clean(type: Delete) { delete rootProject.buildDir }
一共有八个类代码如下: package com.qf.myqfpay;
import android.text.TextUtils; import android.util.Base64; import android.util.Log;
import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec;
/**
-
签名工具
-
用户的公钥必须放到
-
这个下面来通过这个来判断 */ public class CipherUtil { private static final String TAG = "CipherUtil";
private static final String SIGN_ALGORITHMS = "SHA256WithRSA"; //这个是公钥替换地址 private static final String PUBLIC_KEY = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAl8YBI1jOQvXUETCCqFEqHmwff7mMpjp5Lo+MajOcsBwa6ZgIu75AAKu7p2qrGy25bXgtpsYkQItAld3PEijk7FQ9oDDSrozWdOBKWZXHfUSe6hLH5NTGWdcF/HdZUaviBGe60HazB2y3/UYD1p5TV/DRoN+cUAkAo6VMvTemNB3sDSu52DllDyiT0ozNrI1mNhhmAwI1UXaa/QkrtUUuDHS6k7oRYT0XLNWTZGZXBP8iNG1epciOhpuDDmRPEnIkMuO5+g4KP/RNB1gvl6t1eIEW2hAredvr6qpp/OcwA/SRFJm2MULWG23GhjSDxRMDuvdsISrDfip+gq8Z+ZibUQClipEGfOHgE1TYKPCvAmwVTtWXb0WyGNYp6cuNMHJIuINnZo5fqNCaeKD21ZSe60X0PvLmxx3q0R6AvdLahNthMOZ+DPtMPoSEvZYQquVcbGL9VNZXzgS7vzEgvR/vQ//XwlRPdKuxxIrU0fVDdPwxM8StZjJYeda/dgy4d/PxAgMBAAE=";
/**
-
the method to check the signature for the data returned from the interface
-
@param content Unsigned data
-
@param sign the signature for content
-
@param publicKey the public of the application
-
@return boolean */ public static boolean doCheck(String content, String sign, String publicKey) { if (TextUtils.isEmpty(publicKey)) { Log.e(TAG, "publicKey is null"); return false; }
if (TextUtils.isEmpty(content) || TextUtils.isEmpty(sign)) { Log.e(TAG, "data is error"); return false; }
try { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); byte[] encodedKey = Base64.decode(publicKey, Base64.DEFAULT); PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS); signature.initVerify(pubKey); signature.update(content.getBytes("utf-8")); boolean bverify = signature.verify(Base64.decode(sign, Base64.DEFAULT)); return bverify;
} catch (NoSuchAlgorithmException e) { Log.e(TAG, "doCheck NoSuchAlgorithmException" + e); } catch (InvalidKeySpecException e) { Log.e(TAG, "doCheck InvalidKeySpecException" + e); } catch (InvalidKeyException e) { Log.e(TAG, "doCheck InvalidKeyException" + e); } catch (SignatureException e) { Log.e(TAG, "doCheck SignatureException" + e); } catch (UnsupportedEncodingException e) { Log.e(TAG, "doCheck UnsupportedEncodingException" + e); } return false; }
/**
- get the publicKey of the application
- During the encoding process, avoid storing the public key in clear text.
- @return publickey */ public static String getPublicKey(){ return PUBLIC_KEY; }
-
}
/**
-
错误码信息 / public class Constants { /* 用于拉起 pmsPay 页面的 requestCode */ public static final int REQ_CODE_BUY = 4002;
/** requestCode 用于拉出 isEnvReady 接口的登录页面 */ public static final int REQ_CODE_LOGIN = 2001; }
package com.qf.myqfpay;
import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity;
import com.huawei.hms.iap.Iap; import com.huawei.hms.iap.IapClient; import com.huawei.hms.iap.entity.InAppPurchaseData; import com.huawei.hms.iap.entity.OrderStatusCode; import com.huawei.hms.iap.entity.OwnedPurchasesResult; import com.huawei.hms.iap.entity.ProductInfo; import com.huawei.hms.iap.entity.ProductInfoResult; import com.huawei.hms.iap.entity.PurchaseIntentResult; import com.huawei.hms.iap.entity.PurchaseResultInfo; import com.huawei.hms.support.api.client.Status;
import org.json.JSONException;
import java.util.ArrayList; import java.util.List;
/**
-
消耗品 */ public class ConsumptionActivity extends AppCompatActivity { private static final String PURCHASETOKEN_KEY = "purchasetokenSet"; private static final String GEMS_COUNT_KEY = "gemsCount"; private static final String DATA_NAME = "database";
private String TAG = "ConsumptionActivity"; private TextView countTextView; //产品显示列表 private ListView consumableProductsListview; //产品获取集合 private List consumableProducts = new ArrayList(); //产品列表适配器 private ProductListAdapter adapter; //历史记录 private Button purchaseHisBtn; //华为提供接口类 private IapClient mClient; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_consumption); mClient = Iap.getIapClient(this); initView(); //检查是否存在用户已购买但未发货的消耗品。 queryPurchases(null); }
private void initView() { findViewById(R.id.progressBar).setVisibility(View.VISIBLE); findViewById(R.id.content).setVisibility(View.GONE); countTextView = (TextView) findViewById(R.id.gems_count); countTextView.setText(String.valueOf(getCountOfGems(this))); consumableProductsListview = (ListView) findViewById(R.id.consumable_product_list1); consumableProductsListview.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { buy(position);
} }); purchaseHisBtn = (Button) findViewById(R.id.enter_purchase_his); purchaseHisBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //历史记录
// Intent intent = new Intent(ConsumptionActivity.this, PurchaseHistoryActivity.class); // startActivity(intent); } }); //获取有几款产品 queryProducts(); }
/**
* 查询产品
* productIds添加产品Id
* 很重要,很重要
*/
private void queryProducts() {
List<String> productIds = new ArrayList<String>();
productIds.add("123456789");
IapRequestHelper.obtainProductInfo(mClient, productIds, IapClient.PriceType.IN_APP_CONSUMABLE, new IapApiCallback<ProductInfoResult>() {
@Override
public void onSuccess(ProductInfoResult result) {
Log.i(TAG, "obtainProductInfo, success");
if (result == null) {
return;
}
if (result.getProductInfoList() != null) {
consumableProducts = result.getProductInfoList();
}
showProducts();
}
@Override
public void onFail(Exception e) {
Log.e(TAG, "obtainProductInfo: " + e.getMessage());
showProducts();
}
});
}
private void showProducts() {
findViewById(R.id.progressBar).setVisibility(View.GONE);
findViewById(R.id.content).setVisibility(View.VISIBLE);
adapter = new ProductListAdapter(ConsumptionActivity.this, consumableProducts);
consumableProductsListview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
/**
* 调用obtainOwnedPurchases接口
* 获取用户已购买但未发货的消耗品数据。
*/
private void queryPurchases(String continuationToken) {
final String tag = "obtainOwnedPurchases";
IapRequestHelper.obtainOwnedPurchases(mClient, IapClient.PriceType.IN_APP_CONSUMABLE, continuationToken, new IapApiCallback<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
if (result == null) {
Log.e(TAG, tag + " result is null");
return;
}
Log.i(TAG, "obtainOwnedPurchases, success");
if (result.getInAppPurchaseDataList() != null) {
List<String> inAppPurchaseDataList = result.getInAppPurchaseDataList();
List<String> inAppSignature= result.getInAppSignature();
for (int i = 0; i < inAppPurchaseDataList.size(); i++) {
final String inAppPurchaseData = inAppPurchaseDataList.get(i);
final String inAppPurchaseDataSignature = inAppSignature.get(i);
deliverProduct(inAppPurchaseData, inAppPurchaseDataSignature);
}
}
if (!TextUtils.isEmpty(result.getContinuationToken())) {
queryPurchases(result.getContinuationToken());
}
}
@Override
public void onFail(Exception e) {
Log.e(TAG, "obtainOwnedPurchases, type=" + IapClient.PriceType.IN_APP_CONSUMABLE + ", " + e.getMessage());
}
});
}
/**
* 交付产品
* @param inAppPurchaseDataStr
* @param inAppPurchaseDataSignature
*/
private void deliverProduct(final String inAppPurchaseDataStr, final String inAppPurchaseDataSignature) {
if (CipherUtil.doCheck(inAppPurchaseDataStr, inAppPurchaseDataSignature, CipherUtil.getPublicKey())) {
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseDataStr);
if (inAppPurchaseDataBean.getPurchaseState() != InAppPurchaseData.PurchaseState.PURCHASED) {
return;
}
String purchaseToken = inAppPurchaseDataBean.getPurchaseToken();
String productId = inAppPurchaseDataBean.getProductId();
if (DeliveryUtils.isDelivered(ConsumptionActivity.this, purchaseToken)) {
Toast.makeText(this, productId + " has been delivered", Toast.LENGTH_SHORT).show();
IapRequestHelper.consumeOwnedPurchase(mClient, purchaseToken);
} else {
if (DeliveryUtils.deliverProduct(this, productId, purchaseToken)) {
Log.i(TAG, "delivery success");
Toast.makeText(this, productId + " delivery success", Toast.LENGTH_SHORT).show();
updateNumberOfGems();
// To consume the product after successfully delivering.
IapRequestHelper.consumeOwnedPurchase(mClient, purchaseToken);
} else {
Log.e(TAG, productId + " delivery fail");
Toast.makeText(this, productId + " delivery fail", Toast.LENGTH_SHORT).show();
}
}
} catch (JSONException e) {
Log.e(TAG, "delivery:" + e.getMessage());
}
} else {
Log.e(TAG, "delivery:" + getString(R.string.verify_signature_fail));
Toast.makeText(this, getString(R.string.verify_signature_fail), Toast.LENGTH_SHORT).show();
}
}
/**
* 更新产品数量
*/
private void updateNumberOfGems() {
// Update the number of gems.
String countOfGems = String.valueOf(DeliveryUtils.getCountOfGems(ConsumptionActivity.this));
countTextView.setText(countOfGems);
}
/**
* 够买产品
* @param index
*/
private void buy(int index) {
ProductInfo productInfo = consumableProducts.get(index);
IapRequestHelper.createPurchaseIntent(mClient, productInfo.getProductId(), IapClient.PriceType.IN_APP_CONSUMABLE, new IapApiCallback<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
if (result == null) {
Log.e(TAG, "result is null");
return;
}
Status status = result.getStatus();
if (status == null) {
Log.e(TAG, "status is null");
return;
}
// You should pull up the page to complete the payment process.
IapRequestHelper.startResolutionForResult(ConsumptionActivity.this, status, Constants.REQ_CODE_BUY);
}
@Override
public void onFail(Exception e) {
//
}
});
}
/**
*
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i(TAG, "onActivityResult");
super.onActivityResult(requestCode, resultCode, data);
//支付成功否
if (requestCode == Constants.REQ_CODE_BUY) {
if (data == null) {
Log.e(TAG, "数据为空");
return;
}
PurchaseResultInfo purchaseIntentResult = Iap.getIapClient(this).parsePurchaseResultInfoFromIntent(data);
switch(purchaseIntentResult.getReturnCode()) {
case OrderStatusCode.ORDER_STATE_CANCEL:
Toast.makeText(this, "订单已取消!", Toast.LENGTH_SHORT).show();
break;
case OrderStatusCode.ORDER_STATE_FAILED:
case OrderStatusCode.ORDER_PRODUCT_OWNED:
queryPurchases(null);
break;
//订单成功
case OrderStatusCode.ORDER_STATE_SUCCESS:
deliverProduct(purchaseIntentResult.getInAppPurchaseData(), purchaseIntentResult.getInAppDataSignature());
break;
default:
break;
}
return;
}
}
/**
* 获取当前产品数量
* @param context Context.
* @return long
*/
public static long getCountOfGems(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(DATA_NAME, Context.MODE_PRIVATE);
long count = sharedPreferences.getLong(GEMS_COUNT_KEY, 0);
return count;
}
}
package com.qf.myqfpay;
import android.content.Context; import android.content.SharedPreferences; import android.text.TextUtils;
import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set;
public class DeliveryUtils { private static final String PURCHASETOKEN_KEY = "purchasetokenSet"; private static final String GEMS_COUNT_KEY = "gemsCount"; private static final String DATA_NAME = "database";
private static Map<String, Integer> getNumOfGems() {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("CProduct01", 5);
map.put("CustomizedCProduct01", 10);
return map;
}
/**
确定购买的商品是否已发货。 @param 上下文上下文。
@param purchasetoken 产品支付时由华为支付服务器生成,
通过InAppPurchaseData返回给应用。 @return 布尔值
*/
public static boolean isDelivered(Context context, String purchasetoken) {
SharedPreferences sharedPreferences = context.getSharedPreferences(DATA_NAME, Context.MODE_PRIVATE);
Set<String> stringSet = sharedPreferences.getStringSet(PURCHASETOKEN_KEY, null);
if (stringSet != null && stringSet.contains(purchasetoken)) {
return true;
}
return false;
}
/**
* Ship and return the shipping result.
* @param context Context.
* @param productId Id of the purchased product.
* @param purchaseToken Generated by the Huawei payment server during product payment and returned to the app through InAppPurchaseData.
* @return boolean
*/
public static boolean deliverProduct(Context context, String productId, String purchaseToken) {
if (TextUtils.isEmpty(productId) || TextUtils.isEmpty(purchaseToken)) {
return false;
}
if (!getNumOfGems().containsKey(productId)) {
return false;
}
SharedPreferences sharedPreferences = context.getSharedPreferences(DATA_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
long count = sharedPreferences.getLong(GEMS_COUNT_KEY, 0);
count += getNumOfGems().get(productId);
editor.putLong(GEMS_COUNT_KEY, count);
Set<String> stringSet = sharedPreferences.getStringSet(PURCHASETOKEN_KEY, new HashSet<String>());
stringSet.add(purchaseToken);
editor.putStringSet(PURCHASETOKEN_KEY, stringSet);
return editor.commit();
}
/**
* 获取当前产品数量.
* @param context Context.
* @return long
*/
public static long getCountOfGems(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(DATA_NAME, Context.MODE_PRIVATE);
long count = sharedPreferences.getLong(GEMS_COUNT_KEY, 0);
return count;
}
}
package com.qf.myqfpay;
/**
-
用于从 IAP api 回调结果.
-
@since 2019/12/9 */ public interface IapApiCallback {
/** 请求成功。 @param result 成功响应的结果。 */ void onSuccess(T result);
/** 回调失败。 @param e 来自 IAPSDK 的异常。 */ void onFail(Exception e); }
package com.qf.myqfpay;
import android.app.Activity; import android.content.IntentSender; import android.util.Log;
import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hmf.tasks.Task; import com.huawei.hms.iap.IapApiException; import com.huawei.hms.iap.IapClient; import com.huawei.hms.iap.entity.ConsumeOwnedPurchaseReq; import com.huawei.hms.iap.entity.ConsumeOwnedPurchaseResult; import com.huawei.hms.iap.entity.OwnedPurchasesReq; import com.huawei.hms.iap.entity.OwnedPurchasesResult; import com.huawei.hms.iap.entity.ProductInfoReq; import com.huawei.hms.iap.entity.ProductInfoResult; import com.huawei.hms.iap.entity.PurchaseIntentReq; import com.huawei.hms.iap.entity.PurchaseIntentResult; import com.huawei.hms.support.api.client.Status;
import java.util.List;
public class IapRequestHelper { private final static String TAG = "IapRequestHelper";
/**
* 获取在 AppGallery Connect 中配置的应用内产品详细信息。
*
* @param iapClient IapClient 实例调用获取产品信息 API。
* @param productIds 要查询的产品 ID 列表。每个产品 ID
* 必须存在并且在当前应用中是唯一的。
* @param type 应用内产品类型。该值包含:
* 0:消耗品 1:不可消耗品 2 自动更新订阅
* @param callback IapApiCallback
*/
public static void obtainProductInfo(IapClient iapClient, final List<String> productIds, int type, final IapApiCallback callback) {
Log.i(TAG, "call obtainProductInfo");
Task<ProductInfoResult> task = iapClient.obtainProductInfo(createProductInfoReq(type, productIds));
task.addOnSuccessListener(new OnSuccessListener<ProductInfoResult>() {
@Override
public void onSuccess(ProductInfoResult result) {
Log.i(TAG, "obtainProductInfo, success");
callback.onSuccess(result);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "obtainProductInfo, fail");
callback.onFail(e);
}
});
}
/**
* 创建一个 ProductInfoReq 对象。
*
* @param type 应用内产品类型。该值包含: 0:消耗品 1:非消耗品 2
* 自动续订订阅 @param productIds
* 要查询的产品 ID 列表。每个产品
* ID 必须存在并且在当前应用中是唯一的。
* @return 产品信息请求
*/
private static ProductInfoReq createProductInfoReq(int type, List<String> productIds) {
ProductInfoReq req = new ProductInfoReq();
req.setPriceType(type);
req.setProductIds(productIds);
return req;
}
/**
* 查询所有已订阅的应用内商品信息,包括消耗品、非消耗品和自动续期订阅。
* 如果返回消耗品,则系统需要进行交付并调用consumeOwnedPurchase API 来消费产品。
* 如果退回非消耗品,则无需消耗应用内商品。如果返回订阅,
* 则返回该用户在该应用下的所有现有订阅关系。
*
* @param mClient IapClient 实例调用获取OwnedPurchases API。
* @param type 应用内产品类型。该值包含:
* 0:消耗品
* 1:不可消耗品
* 2 自动更新订阅
* @param callback IapApiCallback
*/
public static void obtainOwnedPurchases(IapClient mClient, final int type, String continuationToken, final IapApiCallback callback) {
Log.i(TAG, "call obtainOwnedPurchases");
Task<OwnedPurchasesResult> task = mClient.obtainOwnedPurchases(IapRequestHelper.createOwnedPurchasesReq(type, continuationToken));
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
Log.i(TAG, "obtainOwnedPurchases, success");
callback.onSuccess(result);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "obtainOwnedPurchases, fail");
callback.onFail(e);
}
});
}
/**
* 创建一个OwnedPurchasesReq 对象。 @param type type 应用内商品类型。该值包含:
* 0:消耗品 1:不可消耗品 2 自动更新订阅 @param continuationToken
* 从获取OwnedPurchases api 或获取OwnedPurchaseRecord api 返回的数据位置标志。
* @return OwnedPurchasesReq
*/
private static OwnedPurchasesReq createOwnedPurchasesReq(int type, String continuationToken) {
OwnedPurchasesReq req = new OwnedPurchasesReq();
req.setPriceType(type);
req.setContinuationToken(continuationToken);
return req;
}
/**
使用 priceType 0 消费所有未消费的购买。
@param iapClient IapClient 实例调用消耗 OwnedPurchase API。
@param purchaseToken 在产品支付过程中由华为支付服务器生成,
通过InAppPurchaseData返回给应用。
*/
public static void consumeOwnedPurchase(IapClient iapClient, String purchaseToken) {
Log.i(TAG, "call consumeOwnedPurchase");
Task<ConsumeOwnedPurchaseResult> task = iapClient.consumeOwnedPurchase(createConsumeOwnedPurchaseReq(purchaseToken));
task.addOnSuccessListener(new OnSuccessListener<ConsumeOwnedPurchaseResult>() {
@Override
public void onSuccess(ConsumeOwnedPurchaseResult result) {
// Consume success.
Log.i(TAG, "consumeOwnedPurchase success");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException)e;
int returnCode = apiException.getStatusCode();
Log.e(TAG, "consumeOwnedPurchase fail, IapApiException returnCode: " + returnCode);
} else {
// Other external errors
Log.e(TAG, e.getMessage());
}
}
});
}
/**
创建一个 ConsumeOwnedPurchaseReq 对象。
@param purchaseToken 在产品支付过程中由华为支付服务器生成,
通过InAppPurchaseData返回给应用。应用程序将此参数传递给华为支付服务器更新订单状态,
然后交付应用程序内产品。 @return ConsumeOwnedPurchaseReq
*/
private static ConsumeOwnedPurchaseReq createConsumeOwnedPurchaseReq(String purchaseToken) {
ConsumeOwnedPurchaseReq req = new ConsumeOwnedPurchaseReq();
req.setPurchaseToken(purchaseToken);
req.setDeveloperChallenge("testConsume");
return req;
}
/**
在 PMS @param iapClient IapClient 实例中为应用内产品创建订单以调用
createPurchaseIntent API。要支付的应用内商品的
@param productId ID。应用内产品 ID 是您在
AppGallery Connect 中的应用内产品配置过程中设置的产品 ID。
@param type 应用内产品类型。该值包含:
0:消耗品 1:不可消耗品 2 自动更新订阅 @param callback IapApiCallback
*/
public static void createPurchaseIntent(final IapClient iapClient, String productId, int type, final IapApiCallback callback) {
Log.i(TAG, "call createPurchaseIntent");
Task<PurchaseIntentResult> task = iapClient.createPurchaseIntent(createPurchaseIntentReq(type, productId));
task.addOnSuccessListener(new OnSuccessListener<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
Log.i(TAG, "createPurchaseIntent, success");
callback.onSuccess(result);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "createPurchaseIntent, fail");
callback.onFail(e);
}
});
}
/**
* 创建一个 PurchaseIntentReq 对象。 @param type 应用内产品类型。该值包含:
* 0:消耗品
* 1:非消耗品
* 2 自动更新订阅 @param productId 要支付的应用内商品的 ID。
* 应用内产品 ID 是您在 AppGallery Connect
* 中的应用内产品配置过程中设置的产品 ID。
* @return PurchaseIntentReq
*/
private static PurchaseIntentReq createPurchaseIntentReq(int type, String productId) {
PurchaseIntentReq req = new PurchaseIntentReq();
req.setPriceType(type);
req.setProductId(productId);
req.setDeveloperPayload("testPurchase");
return req;
}
/**
开始一项活动。
@param activity 启动新页面的活动。
@param status 该参数包含支付页面的pendingIntent 对象。
@param reqCode 结果代码.
*/
public static void startResolutionForResult(Activity activity, Status status, int reqCode) {
if (status == null) {
Log.e(TAG, "status is null");
return;
}
if (status.hasResolution()) {
try {
status.startResolutionForResult(activity, reqCode);
} catch (IntentSender.SendIntentException exp) {
Log.e(TAG, exp.getMessage());
}
} else {
Log.e(TAG, "intent is null");
}
}
}
package com.qf.myqfpay;
import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView;
import com.huawei.hms.iap.IapClient; import com.huawei.hms.iap.entity.ProductInfo;
import java.util.List;
/**
-
列表适配器 */ public class ProductListAdapter extends BaseAdapter { private Context mContext; private List productInfos;
public ProductListAdapter(Context context, List productInfos) { mContext = context; this.productInfos = productInfos; } @Override public int getCount() { return productInfos.size(); }
@Override public View getView(int position, View convertView, ViewGroup parent) { ProductInfo productInfo = productInfos.get(position); ProductListViewHolder holder = null; if (null == convertView) { convertView = LayoutInflater.from(mContext).inflate(R.layout.item_layout, null); holder = new ProductListViewHolder(convertView); convertView.setTag(holder); } else { holder = (ProductListViewHolder) convertView.getTag(); }
holder.productName.setText(productInfo.getProductName()); holder.productPrice.setText(productInfo.getPrice()); if (productInfo.getPriceType() == IapClient.PriceType.IN_APP_NONCONSUMABLE) { holder.imageView.setVisibility(View.GONE); } return convertView;
}
@Override public long getItemId(int position) { return position; }
@Override public Object getItem(int position) { if (productInfos != null && productInfos.size() > 0) { return productInfos.get(position); } return null; }
static class ProductListViewHolder { TextView productName; TextView productPrice; ImageView imageView;
ProductListViewHolder(View view) { productName = (TextView) view.findViewById(R.id.item_name); productPrice = (TextView) view.findViewById(R.id.item_price); imageView = (ImageView) view.findViewById(R.id.item_image); }
} }
package com.qf.myqfpay;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView xiaoPay, feiPay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
xiaoPay = findViewById(R.id.tv);
feiPay = findViewById(R.id.tv_fei);
xiaoPay.setOnClickListener(this);
feiPay.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv:
startActivity(new Intent(this,ConsumptionActivity.class));
break;
case R.id.tv_fei:
break;
default:
break;
}
}
}