zoukankan      html  css  js  c++  java
  • Google In-App Billing 实现(内含Unity 实现经验)

    实现内购计费

    傻逼目录

     
      Adding the AIDL file
    1. Updating Your Manifest
    2. Creating a ServiceConnection
    3. Making In-app Billing Requests
        Querying Items Available for Purchase
      1. Purchasing an Item
      2. Querying Purchased Items
      3. Consuming a Purchase
      4. Implementing Subscriptions
    4. Securing Your App

    二逼参考

      In-app Billing Reference (V3)

    根本无法执行的例子

      Sample Application (V3)

    也看

      Selling In-app Products

     Google Play 的 In-app Billing 提供了一种直(hui)观(se)简(nan)单(dong)的接口, 提供向GooglePlay发送内购请求和管理GooglePlay内购交易的功能。这都基于V3版本的API

    测试你的程序的教程,参见  Selling In-app Products 训练课程. 教程提供了完整的内购示例。

    包含方便的类库,用于从google play设置你的连接,发送账单,购买响应,以及管理后台线程让你可以在主线程调用内购。

    在此之前,确保你阅读了 In-app Billing Overview 以了解内购的基本概念,让你更容易实现内购。

    实现内购,你需要

    1. IInAppBillingService库文件植入你的项目
    2. AndroidManifest.xml 文件
    3. ServiceConnection 并绑定到 IInAppBillingService.
    4. 添加 AIDL 文件到你的工程

    是一个 Android Interface Definition Language (AIDL) 文件他定义了V3版内购服务的接口,你可以使用这些接口,通过IPC方法的方式调用函式,创建账单请求

    获取ADIL:

    1. Android SDK Manager.
    2. Extras 段
    3. 选择Google Play Billing Library.
    4. 点击Install packages 完成下载

     sdk/extras/google/play_billing/.

    具体来说:

    1. 首先,下载 Google Play Billing Library到你的安卓工程
        Tools > Android > SDK Manager.(2.0版AS-File->Settings)
      1. SDK Tools 子页下载下一步,拷贝  文件到你的工
          原文都是垃圾,直接创建src/com/android/vending/billing/
        1. 把文件考进去,拉倒。
        2. 原文说需要Gradle编译,没有也一样,直接打个APK试试,对应文件就会自己生成!
      2. 编译你的工程.编译出IInAppBillingService.java
      3. 需要用gradle编译一下,但是已经编好的也可以直接拿过来用(别听他的!)。(重要的事情说3遍,Unity用户请不要用AS,用Eclipse)X3。

    更新你的 App的 Manifest

    不翻译了,废话那么多,直接加上这句拉倒

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

    创建一个 ServiceConnection

    你的APP必须有一个 ServiceConnection 来协助你的APP和GooglePlay之间的消息传递,至少你应该:

    • IInAppBillingService.
    • 向 IInAppBillingService 发送账单
    为了和GooglePlay上的内购服务建立连接,你需要实现一个 ServiceConnection 并把你的Activity绑定到IInAppBillingService

    重写onServiceDisconnected 和 onServiceConnected 方法,在建立连接后获得IInAppBillingService实例的引用

    IInAppBillingService mService;
    ServiceConnection mServiceConn =newServiceConnection(){
    @Override
    publicvoid onServiceDisconnected(ComponentName name){
    =null;
    }
    @Override
    publicvoid onServiceConnected(ComponentName name,
    IBinder service){
    =IInAppBillingService.Stub.asInterface(service);
    }
    };

    onCreate 方法中,调用 bindService 方法绑定. 把 Intent 传给方法,他代表内购服务。再传入一个你刚刚创建的 ServiceConnection 的实例,并且显式的设定你的Intent的包名为  使用如下所示的setPackage() 方法时刻确保显示的设置intent的目标包名为@Override
    publicvoid onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    (R.layout.activity_main);
    Intent serviceIntent =
    newIntent("com.android.vending.billing.InAppBillingService.BIND");
    .setPackage("com.android.vending");
    (serviceIntent, mServiceConn,Context.BIND_AUTO_CREATE);
    }

    现在你可以使用mService的引用去和GooglePlay Service通信了。

    重要: 当你的Activity嗝屁的时候记住对你的mService解绑。不然他会让你的(其实是用户的,不关你屁事)设备变慢。如何解绑看下面:

    @Override
    publicvoid onDestroy(){
    super.onDestroy();
    if(mService !=null){
    (mServiceConn);
    }
    }

    (没让你看JJ,看上面的代码块)

    全套实现Selling In-app Products 训练课程,和附件例子。

    创建In-app Billing请求

    一旦你的应用程序连接到 Google Play, 你就可以初始化内购商品了。 GooglePlay提供了校验接口,使用户可以进入他们的支付方法,所以你的应用程序不必自己处理支付事务。

    当一个物品被购买,GooglePlay会识别这个用户对那个物品的所有权,并且防止他购买相同id的产品,直到这个物件被消费掉。

    你可以在你的APP里面控制物品如何被消耗掉(通常买了就应该马上消耗掉,这样客户才能再买),并通知GooglePlay,那个商品可以被再次购买。

    你也可以快速的向GooglePlay查询为用户建立的物品购买清单。这很有用,例如,当你的用户启动APP时,你可能需要为他恢复购买。

    为购买查询可购买商品

    在你的APP里,你可以利用V3内购API向GooglePlay查询商品的细节。你需要把一个请求发给In-app Billing 服务。

    首先创建一个Bundle 他包含一个记录商品ID的,键值为"ITEM_ID_LIST"的字符串 ArrayList列表 , 每一个ID都是一个可购买商品。

    ArrayList<String> skuList =newArrayList<String>();
    .add("premiumUpgrade");
    .add("gas");
    Bundle querySkus =newBundle();
    .putStringArrayList(“ITEM_ID_LIST”, skuList);

    getSkuDetails 方法,

    getPackageName()

    Bundle skuDetails = mService.getSkuDetails(3,
    (),"inapp", querySkus);

    如果请求成功,返回的bundle将会有返回值代码 BILLING_RESPONSE_RESULT_OK (0).

    getSkuDetails 方法. 调用这个方法会触发一个网络请求并阻塞主线程。

    作为替代,创建一个单独线程,并在其中调用getSkuDetails。(不会Java,你倒是说说怎么创建线程)

    如果你想指定所有的可能的返回代码的意义,去看 In-app Billing Reference.(我不知道,也不想知道!)

    查询结果被存在一个key为DETAILS_LIST的字符串ArrayList中。购买信息以字符串形式存于JSON格式中。

    想要获取返回的产品细节信息,参照 In-app Billing Reference.

    在这个例子中,你从前面代码块里创建的skuDetails 这个bundle里面,取得你的内购商品价格。

    int response = skuDetails.getInt("RESPONSE_CODE");

    if(response ==0){
    ArrayList<String> responseList
    = skuDetails.getStringArrayList("DETAILS_LIST");
    for(String thisResponse : responseList){
    JSONObjectobject=newJSONObject(thisResponse);
    String sku =object.getString("productId");
    String price =object.getString("price");
    if(sku.equals("premiumUpgrade")) mPremiumUpgradePrice = price;
    elseif(sku.equals("gas")) mGasPrice = price;
    }
    }
    PS:估计你得自己搞一张CSV表,或其他什么的,存放你的商品,然后对应返回信息,来更新UI,显示给玩家。客户端有而服务器不存在的商品,或被下架的商品,是不应该显示给玩家的。
    购买一个商品

    Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
    ,"inapp","bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

    Bundle 会有返回值代码 BILLING_RESPONSE_RESULT_OK (0) 和一个 PendingIntent (这又是啥逼玩意啊!)你可以用他们启动一个购买流程。

    BUY_INTENT从返回的Bundle 提取 PendingIntent .

    PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");

    想要完成购买事务,需要调用 startIntentSenderForResult 方法,并使用之前创建的 PendingIntent 。在这个栗子里面,你使用一个随意的值1001作为请求码。

    startIntentSenderForResult(pendingIntent.getIntentSender(),
    1001,newIntent(),Integer.valueOf(0),Integer.valueOf(0),
    Integer.valueOf(0));

    PendingIntent 到你的APP的 onActivityResult 方法中。 onActivityResult 方法会得到一个返回值为Activity.RESULT_OK (1) 或Intent中全部返回订单 的信息,访问 In-app Billing Reference.

    INAPP_PURCHASE_DATA 键值,在返回 Intent,举个栗子:

    '{
    "opaque-token-up-to-1000-characters"
     }'

    此令牌是一个不可读的字符序列,最长1000个字符. 将这个令牌整个传入其他方法,比如当你想消耗购买时,正如 Consume a Purchase. 中提到的。不要省略或者改变令牌的大小写,你需要保存整个令牌。

    Intent的签名。

    @Override
    protectedvoid onActivityResult(int requestCode,int resultCode,Intent data){
    if(requestCode ==1001){
    int responseCode = data.getIntExtra("RESPONSE_CODE",0);
    String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
    String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
    if(resultCode == RESULT_OK){
    try{
    JSONObject jo =newJSONObject(purchaseData);
    String sku = jo.getString("productId");
    ("You have bought the "+ sku +". Excellent choice,
    );
    }
    catch(JSONException e){
    ("Failed to parse purchase data.");
    .printStackTrace();
    }
    }
    }
    }

    developerPayload中,你可以随机的生成一个字符串令牌。

    当你从GooglePlay获取购买响应,确保验证返回数据的前面,orderId和developerPayload 字符串。

    附加的安全性:你应该在你自己的安全服务器上,检测这些东西。

    确保你的orderId是一个你之前没用过的唯一值。并且developerPayload字符串和你之前随购买请求发送的令牌相互匹配。 

    查询已购商品

    要从应用程序检索用户的购买的信息,调用V3 API的 getPurchases 方法。参数传入版号3,包名和“inapp”类别(订阅为“subs”)
    Bundle ownedItems = mService.getPurchases(3, getPackageName(),"inapp",null);

    Bundle 返回代码0. 

    Bundle 同时也包含一个产品IDs列表,标记每一个产品的细节和签名。

    getPurchase 调用顺序为基准。

    Bundle 会返回INAPP_CONTINUATION_TOKEN 暗示还有更多的商品可以获得。你可以用这个token作为参数,进行后续的getPurchases 请求。

    int response = ownedItems.getInt("RESPONSE_CODE");
    if(response ==0){
    ArrayList<String> ownedSkus =
    .getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
    ArrayList<String>  purchaseDataList =
    .getStringArrayList("INAPP_PURCHASE_DATA_LIST");
    ArrayList<String>  signatureList =
    .getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
    String continuationToken =
    .getString("INAPP_CONTINUATION_TOKEN");
    for(int i =0; i < purchaseDataList.size();++i){
    String purchaseData = purchaseDataList.get(i);
    String signature = signatureList.get(i);
    String sku = ownedSkus.get(i);


    }


    }

    消耗一个购买

    consumePurchase 方法到 In-app Billing service 并且将标记将要被移除的购买的purchaseToken 作为参数传入。

    INAPP_PURCHASE_DATA 返回的字符串包含了这次要用的purchaseToken ,他在token变量里面,这就是为什么上面的说明要求你自己记录token。

    int response = mService.consumePurchase(3, getPackageName(), token);

    警告: 别在主线程调用这个方法,建立独立的子线程干这个事。否则他会阻塞你的主线程。

    实现订阅

    Bundle bundle = mService.getBuyIntent(3,"com.example.myapp",
       MY_SKU,"subs", developerPayload);
    PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
    if(bundle.getInt(RESPONSE_CODE)== BILLING_RESPONSE_RESULT_OK){


    (pendingIntent, RC_BUY,newIntent(),
    Integer.valueOf(0),Integer.valueOf(0),Integer.valueOf(0));
    }

    Bundle activeSubs = mService.getPurchases(3,"com.example.myapp",
    "subs", continueToken);

    保护你的APP

    在 Developer Console,打开你的application's details,然后点击Your License Key for This Application.

    由狗狗Play生成的 Base64-encoded RSA 公钥使用二进制编码, X.509 subjectPublicKeyInfo DER SEQUENCE 格式. 他与狗狗Play的许可是同一级别的。

     Security and Design.


  • 相关阅读:
    INT最值
    约瑟夫问题
    word里的图片怎么复制出来
    必须掌握的8个dos命令
    vld(Visual Leak Detector 内存泄露检测工具
    sscanf,sscanf_s及其相关用法
    游戏开发梦开始的地方笔记
    关于字符编码,你所需要知道的
    CreateMutex创建互斥体可以用于只运行进程的一个实例
    sprintf,你知道多少?
  • 原文地址:https://www.cnblogs.com/android-blogs/p/6398718.html
Copyright © 2011-2022 走看看