Google商店的应用被下架,应用内购买必须走Google支付,还要扣去百分之三十的手续费,而且有些国家还会收一定的销售税最高达27%,其实Google支付只是自己集成了Paypal支付和银行卡支付,然后Google收手续费。用户使用Google正常支付退款时间是48小时,退款只会在商家账号通知。
我们来谈一谈集成Google支付吧:
Google上给出了Demo:https://github.com/cafebazaar/TrivialDrive
里面有购买订阅和受管理产品的,大家可以下载运行一下试一试。我刚开始是按照Google开发文档去集成的,可能是我水平有限,并没有成功。最后是按Demo去搞吧,方便。Google给出的API:https://developer.android.com/google/play/billing/billing_integrate.html
要在您的应用中实现应用内购买结算,您需要执行以下操作:
AndroidManifest.xml
文件。ServiceConnection
并将其绑定到 IInAppBillingService
。IInAppBillingService
。 IInAppBillingService.aidl
是一种定义应用内购买结算版本 3 服务接口的 Android 接口定义语言 (AIDL) 文件。 您可以使用此接口通过调用 IPC 方法调用来发送结算请求。
要获取 AIDL 文件,请执行以下操作:
Extras
部分。 IInAppBillingService.aidl
文件将安装到
。
要将 AIDL 添加到您的项目,请执行以下操作:
IInAppBillingService.aidl
文件到您的项目。
src/main
。aidl
,再选择 OK。com.android.vending.billing
,再选择 OK。/extras/google/play_billing/
,复制 IInAppBillingService.aidl
文件,然后将其粘贴到项目中的 com.android.vending.billing
软件包。/src/com/android/vending/billing
,并将IInAppBillingService.aidl
文件复制到此目录。 将 AIDL 文件添加到您的项目中并使用 Gradle 工具构建项目,从而生成IInAppBillingService.java
文件。/gen
目录中看到名为 IInAppBillingService.java
的生成文件。 应用内购买结算依赖于 Google Play 应用,后者将处理应用与 Google Play 服务器之间的所有通信。 要使用 Google Play 应用,您的应用必须请求适当的权限。 您可以通过将 com.android.vending.BILLING
权限添加到 AndroidManifest.xml 文件执行此操作。 如果您的应用未声明应用内购买结算权限,但试图发送结算请求,Google Play 将拒绝请求并使用错误响应。
要为您的应用授予必要的权限,请在 AndroidManifest.xml
文件中添加以下代码行:
这个权限是一定得加的。
按照例子,先把所需Google aidl放好,位置一定不能错。
IInAppBillingService.aidl
还有所需的Util,都拷贝到项目中:
然后Clean一下,不让IInAppBillingService不能用。
下面开始代码集成:
先把所需要的常量定义一下:
//google支付部分:
// 声明属性The helper object
private IabHelper mHelper;
private String TAG = "MyLog1";
/**
* Google是否初始化成功:
*/
boolean iap_is_ok = false;
/**
* Google支付需要的
* 购买产品的id
*/
static String purchaseId = "";
// (arbitrary) request code for the purchase flow
//购买请求回调requestcode
static final int RC_REQUEST = 1001;
//base64EncodedPublicKey是在Google开发者后台复制过来的:要集成的应用——>服务和API——>此应用的许可密钥(自己去复制)
String base64EncodedPublicKey = "MIIBIjANBgkqh******************************DAQAB";
在onCreate中初始化:
mHelper = new IabHelper(this, base64EncodedPublicKey);
// enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(true);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
MyLog.i(TAG, "初始化完成.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing:初始化失败 " + result);
return;
}
iap_is_ok = true;
if (mHelper == null) return;
MyLog.i(TAG, "Google初始化成功.");
if (iap_is_ok) {
try {
mHelper.queryInventoryAsync(mGotInventoryListener);
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}else {
MyLog.i(TAG, "Google Play初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
// toast("Google Play初始化失败,当前无法进行支付,请确定您所在地区支持Google Play支付或重启游戏再试!");
}
}
});
// Listener that's called when we finish querying the items and subscriptions we own 查询所有的产品
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
MyLog.i(TAG, "查询库存完成.");
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
// Is it a failure?
if (result.isFailure()) {
complain("查询库存失败: " + result);
return;
}
MyLog.i(TAG, "查询库存成功.");
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
// Check for gas delivery -- if we own gas, we should fill up the tank immediately
//查询你的产品是否存在没有消耗的,要是没有消耗,先去消耗,再购买
Purchase gasPurchase = inventory.getPurchase(purchaseId);
if (gasPurchase != null && verifyDeveloperPayload(gasPurchase))
{
try {
mHelper.consumeAsync(inventory.getPurchase(purchaseId), mConsumeFinishedListener);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error consuming gas. Another async operation in progress.");
}
return;
}
MyLog.i(TAG, "初始库存查询完成;启用主用户界面.");
}
};
/**
* 去购买Google产品
* purchaseId Google产品id
*
* 点击购买的时候,才去初始化产品,看看是否有这个产品,是否消耗
*
*/
private void toBuyGooglepay(){
// launch the gas purchase UI flow.
// We will be notified of completion via mPurchaseFinishedListener
MyLog.i(TAG, "开始购买");
/* TODO: for security, generate your payload here for verification. See the comments on
* verifyDeveloperPayload() for more info. Since this is a SAMPLE, we just use
* an empty string, but on a production app you should carefully generate this. */
//这个payload是要给Google发送的备注信息,自定义参数,购买完成之后的订单中也有该字段
String payload = Contants.userID;
try {
mHelper.launchPurchaseFlow(TypeActivity.this, purchaseId, RC_REQUEST,mPurchaseFinishedListener, payload);
} catch (Exception e) {
Toast.makeText(TypeActivity.this,"无法完成谷歌支付",Toast.LENGTH_SHORT).show();
}
}
1:购买完成的回调事件监听:
// Callback for when a purchase is finished购买完成的回调
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
MyLog.i(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
complain("Error purchasing: " + result);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
return;
}
MyLog.i("MyLog1", "购买完成.");
//购买完成时候就能获取到订单的详细信息:purchase.getOriginalJson(),要是想要什么就去purchase中get
//根据获取到产品的Id去判断是哪一项产品
if (purchase.getSku().equals(purchaseId)) {
MyLog.i(TAG, "购买的是"+purchase.getSku());
try {
//购买完成之后去消耗产品
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error consuming gas. Another async operation in progress.");
return;
}
}
}
};
Google给出的声明:应用内商品一经购买,就会被视为“被拥有”且无法从 Google Play 购买。 您必须对应用内商品发送消耗请求,然后 Google Play 才能允许再次购买。可以消耗托管的应用内商品,但不能消耗订阅。下面是消耗监听:
// Called when consumption is complete 消耗产品的回调
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
MyLog.i(TAG, "消耗完。购买(Purchase): " + purchase + ", result: " + result);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
// We know this is the "gas" sku because it's the only one we consume,
// so we don't check which sku was consumed. If you have more than one
// sku, you probably should check...
if (result.isSuccess()) {
// successfully consumed, so we apply the effects of the item in our
// game world's logic, which in our case means filling the gas tank a bit
MyLog.i(TAG, "消费成功。Provisioning.");
}else {
complain("Error while consuming: " + result);
}
}
};
/** Verifies the developer payload of a purchase. */
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
/*
* TODO: verify that the developer payload of the purchase is correct. It will be
* the same one that you sent when initiating the purchase.
*
* WARNING: Locally generating a random string when starting a purchase and
* verifying it here might seem like a good approach, but this will fail in the
* case where the user purchases an item on one device and then uses your app on
* a different device, because on the other device you will not have access to the
* random string you originally generated.
*
* So a good developer payload has these characteristics:
*
* 1. If two different users purchase an item, the payload is different between them,
* so that one user's purchase can't be replayed to another user.
*
* 2. The payload must be such that you can verify it even when the app wasn't the
* one who initiated the purchase flow (so that items purchased by the user on
* one device work on other devices owned by the user).
*
* Using your own server to store and verify developer payloads across app
* installations is recommended.
*/
return true;
}
void complain(String message) {
MyLog.i(TAG, "**** TrivialDrive Error: " + message);
// alert("Error: " + message);
}
void alert(String message) {
AlertDialog.Builder bld = new AlertDialog.Builder(this);
bld.setMessage(message);
bld.setNeutralButton("OK", null);
MyLog.i(TAG, "Showing alert dialog: " + message);
bld.create().show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (mHelper == null) return;
// Pass on the activity result to the helper for handling
try {
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}else {
MyLog.i("MyLog1", "onActivityResult handled by IABUtil.");
}
} catch (Exception e) {
e.printStackTrace();
}
if (requestCode == 1001) {
int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
//订单信息
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
MyLog.i("MyLog1", "responseCode:: " + responseCode );
MyLog.i("MyLog1", "purchaseData:: " + purchaseData );
MyLog.i("MyLog1", "dataSignature:: " + dataSignature );
if (resultCode == RESULT_OK) {
try {
JSONObject jo = new JSONObject(purchaseData);
//订单Id
String sku = jo.getString("productId");
System.out.println("You have bought the " + sku + ". Excellent choice,adventurer!");
}
catch (JSONException e) {
MyLog.i("MyLog1","Failed to parse purchase data.");
System.out.println("Failed to parse purchase data.");
e.printStackTrace();
}
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mHelper != null) {
try {
mHelper.dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
mHelper = null;
}
在IabHelp.java中的300行左右把:
mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
新建一个绑定的判断:
public boolean isBound;
isBound = mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
public void dispose() throws IabAsyncInProgressException {
synchronized (mAsyncInProgressLock) {
if (mAsyncInProgress) {
throw new IabAsyncInProgressException("Can't dispose because an async operation " +
"(" + mAsyncOperation + ") is in progress.");
}
}
logDebug("Disposing.");
mSetupDone = false;
if (mServiceConn != null) {
logDebug("Unbinding from service.");
if (mContext != null && isBound){
mContext.unbindService(mServiceConn);
isBound = false;
}
}
mDisposed = true;
mContext = null;
mServiceConn = null;
mService = null;
mPurchaseListener = null;
}
首先你得有一个能安装Google play的手机,还要有个Gmail邮箱(不能和Google开发者的Gmail邮箱一样),测试支付不产生订单id,要是需要查看订单id就得真实支付(需要支持双币的信用卡或者paypal账号)。测试用的app一定要跟上传到Google的测试版的包名、版本code、name、签名一致,否则无法进行支付测试。
在Google开发后台:设置-->信息-->设置测试许可中添加你的测试Gmail邮箱(重要,不然会真实扣费)。在应用中的APK选项中,上传一版Bata版,发布,在测试人员中设置你的测试Gmail,和测试许可中的一致
另附Google play billing下载地址:https://github.com/googlesamples/android-play-billing/tree/master/TrivialDrive/app/src/main