Android 消耗性应用程式内购买

示例

消费型被管理产品是指可以多次购买的产品,例如游戏中的货币,游戏寿命,开机状态等。

在此示例中,我们将实现4种不同的耗材管理产品 "item1", "item2", "item3", "item4"。

摘要步骤:

  1. 将应用内结算库添加到您的项目(AIDL文件)中。

  2. 在AndroidManifest.xml文件中添加所需的权限。

  3. 将签名的APK部署到Google Developers Console。

  4. 定义您的产品。

  5. 实施代码。

  6. 测试应用内结算(可选)。

第1步:

首先,我们需要将AIDL文件添加到您的项目中,如此处的Google文档中所述。

IInAppBillingService.aidl是一个Android接口定义语言(AIDL)文件,用于定义应用内结算第3版服务的接口。您将使用此接口通过调用IPC方法调用来发出计费请求。

第2步:

添加AIDL文件后,在中添加BILLING权限AndroidManifest.xml:

<!-- Required permission for implementing In-app Billing -->
<uses-permission android:name="com.android.vending.BILLING" />

第三步:

生成签名的APK,并将其上传到Google Developers Console。这是必需的,以便我们可以在那里开始定义我们的应用内产品。

步骤4:

用不同的productID定义所有产品,并为每个产品设置价格。有2种类型的产品(被管理产品和订阅)。如前所述,我们将实施4种不同的消耗品管理产品 "item1", "item2", "item3", "item4"。

步骤5:

完成上述所有步骤之后,您现在就可以开始在自己的活动中实现代码本身了。

主要活动:

public class MainActivity extends Activity {

    IInAppBillingService inAppBillingService;
    ServiceConnection serviceConnection;

    //每个项目的productID。您应该在Google Developers Console中定义它们。
    final String item1 = "item1";
    final String item2 = "item2";
    final String item3 = "item3";
    final String item4 = "item4";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 根据您的布局文件实例化视图。
        final Button buy1 = (Button) findViewById(R.id.buy1);
        final Button buy2 = (Button) findViewById(R.id.buy2);
        final Button buy3 = (Button) findViewById(R.id.buy3);
        final Button buy4 = (Button) findViewById(R.id.buy4);

        // 每个按钮的setOnClickListener()。
        // buyItem()这是我们将用来启动PurchaseFlow的方法。
        buy1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buyItem(item1);
            }
        });

        buy2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buyItem(item2);
            }
        });

        buy3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buyItem(item3);
            }
        });

        buy4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buyItem(item4);
            }
        });

        // 附加服务连接。
        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
                inAppBillingService = null;
            }

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                inAppBillingService = IInAppBillingService.Stub.asInterface(service);
            }
        };

        // 绑定服务。
        Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
        serviceIntent.setPackage("com.android.vending");
        bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE);

        // 获取每个产品的价格,并将价格设置为文本
        // 每个按钮,以便用户知道每个项目的价格。
        if (inAppBillingService != null) {
            // 注意:您需要在此处创建一个新线程,因为
            // getSkuDetails()触发网络请求,该请求可以
            // 如果它是从主线程调用的,则会导致应用程序滞后。
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    ArrayList<String> skuList = new ArrayList<>();
                    skuList.add(item1);
                    skuList.add(item2);
                    skuList.add(item3);
                    skuList.add(item4);
                    Bundle querySkus = new Bundle();
                    querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

                    try {
                        Bundle skuDetails = inAppBillingService.getSkuDetails(3, getPackageName(), "inapp", querySkus);
                        int response = skuDetails.getInt("RESPONSE_CODE");

                        if (response == 0) {
                            ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");

                            for (String thisResponse : responseList) {
                                JSONObject object = new JSONObject(thisResponse);
                                String sku = object.getString("productId");
                                String price = object.getString("price");

                                switch (sku) {
                                    case item1:
                                        buy1.setText(price);
                                        break;
                                    case item2:
                                        buy2.setText(price);
                                        break;
                                    case item3:
                                        buy3.setText(price);
                                        break;
                                    case item4:
                                        buy4.setText(price);
                                        break;
                                }
                            }
                        }
                    } catch (RemoteException | JSONException e) {
                        e.printStackTrace();
                    }
                }
            });
            thread.start();
        }
    }

    // 通过传递用户想要购买的商品的productID作为参数来启动PurchaseFlow。
    private void buyItem(String productID) {
        if (inAppBillingService != null) {
            try {
                Bundle buyIntentBundle = inAppBillingService.getBuyIntent(3, getPackageName(), productID, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
                PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
                startIntentSenderForResult(pendingIntent.getIntentSender(), 1003, new Intent(), 0, 0, 0);
            } catch (RemoteException |IntentSender.SendIntentExceptione) {
                e.printStackTrace();
            }
        }
    }

    //在onDestroy()中解除服务绑定。如果您不取消绑定,则打开
    // 服务连接可能会导致设备性能下降。
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (inAppBillingService != null) {
            unbindService(serviceConnection);
        }
    }

    //在此处检查应用内购买是否成功。如果成功的话
    // 然后使用产品,然后让应用进行所需的更改。
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 1003 && resultCode == RESULT_OK) {

            final String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");

            // 注意:您需要在此处创建一个新线程,因为
            // abusePurchase()触发网络请求,该请求可以
            // 如果它是从主线程调用的,则会导致应用程序滞后。
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        JSONObject jo = new JSONObject(purchaseData);
                        // 获取所购买商品的productID。
                        String sku = jo.getString("productId");
                        String productName = null;

                        // 增加硬币()这里是在游戏中用作示例的方法
                        // 如果购买成功,则增加游戏内货币。
                        // 您应该在此处实现自己的代码,然后让该应用程序应用
                        // 购买成功后需要进行的更改。
                        switch (sku) {
                            case item1:
                                productName = "Item 1";
                                increaseCoins(2000);
                                break;
                            case item2:
                                productName = "Item 2";
                                increaseCoins(8000);
                                break;
                            case item3:
                                productName = "Item 3";
                                increaseCoins(18000);
                                break;
                            case item4:
                                productName = "Item 4";
                                increaseCoins(30000);
                                break;
                        }

                        // 进行购买,以便用户能够再次购买相同的产品。
                        inAppBillingService.consumePurchase(3, getPackageName(), jo.getString("purchaseToken"));
                        Toast.makeText(MainActivity.this, productName + " is successfully purchased. Excellent choice, master!", Toast.LENGTH_LONG).show();
                    } catch (JSONException | RemoteException e) {
                        Toast.makeText(MainActivity.this, "无法解析购买数据。", Toast.LENGTH_LONG).show();
                        e.printStackTrace();
                    }
                }
            });
            thread.start();
        }
    }
}

步骤6:

实施代码后,您可以通过将apk部署到beta / alpha通道进行测试,并让其他用户为您测试代码。但是,在测试模式下无法进行真正的应用内购买。您必须先将您的应用/游戏发布到Play商店,以便完全激活所有产品。

有关测试应用内结算的更多信息,请点击此处。