Android InAppBilling - 当用户按下购买按钮时该怎么办?

时间:2012-06-19 11:08:48

标签: android

我在本地设置了“Dungeons”InAppBilling示例,我准备尝试一下,但我有点困惑。我有一个这样的按钮:

Button donate = (Button)findViewById(R.id.donate);     
donate.setOnClickListener(new Button.OnClickListener() {  
        public void onClick(View v) {     
        // But what do I do here? :)
        }
});

当它被调用时,我需要做什么才能真正进入Android商店的付费界面?

谢谢!

6 个答案:

答案 0 :(得分:4)

我建议你使用这段代码,因为这个例子安静简单,起初很容易处理..你要做的事情是

http://blog.blundell-apps.com/simple-inapp-billing-payment/

  1. 从上面的链接下载示例项目代码(在底部有代码描述和下载链接)
  2. 在您想要在app billing中实现的android项目中,创建包com.android.vending.billing并放置IMarketBillingService.aidl(您可以在步骤1中下载的项目中找到此文件和下面提到的所有文件)< / LI>
  3. 将以下实用程序文件放在任何包中,并相应地更正导入语句。

          * BillingHelper.java
          * BillingReceiver.java
          * BillingSecurity.java
          * BillingService.java
          * C.java
    
  4. 在BillingSecurity.java中放置公钥(您可以在编辑个人资料底部的开发者控制台中找到它)String base64EncodedPublicKey = "your public key here"

  5. 在清单中声明以下权限(在应用程序标记之外),服务和接收者(在应用程序标记内),如下所示(也可以查看代码中的清单以供参考)

     //outside the application tag 
     <uses-permission android:name="com.android.vending.BILLING" />
    
     // Inside the application tag
     <service android:name=".BillingService" />
    
    <receiver android:name=".BillingReceiver">
        <intent-filter>
            <action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
            <action android:name="com.android.vending.billing.RESPONSE_CODE" />
            <action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />            
        </intent-filter>
    </receiver> 
    
  6. 将上述代码放在您举行购买活动的地方。

    //at the starting of your onCreate()
    startService(new Intent(mContext, BillingService.class));
    BillingHelper.setCompletedHandler(mTransactionHandler);
    
    //outside onCreate() Within class
     public Handler mTransactionHandler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            Log.i(TAG, "Transaction complete");
            Log.i(TAG, "Transaction status: "+BillingHelper.latestPurchase.purchaseState);
            Log.i(TAG, "Item purchased is: "+BillingHelper.latestPurchase.productId);
    
            if(BillingHelper.latestPurchase.isPurchased()){
                //code here which is to be performed after successful purchase
            }
        };
    
     };
    
     //code to initiate a purchase... can be placed in onClickListener etc
      if(BillingHelper.isBillingSupported()){
            BillingHelper.requestPurchase(mContext, "android.test.purchased"); 
            // where android.test.purchased is test id for fake purchase, when you create products through developer console you can set a code to pass the id(which is given on developer console while creating a product) of the item which is selected for purchase to intiate purchase of that item.
        } else {
            Log.i(TAG,"Can't purchase on this device");
             // Do Anything Heer to show user that purchase not possible on this device
        }
    
  7. 注意:要进行测试购买,您需要将公钥放在BillingSecurity.java中,如上所述,其次您需要将apk上传到开发者控制台(您可以将其保留为uupublished和unactive),其次您需要一个真实的更新了Play商店应用程序的Android设备(模拟器不起作用)。

    注意:在应用内购买所需的帐户以及上述所有讨论中描述的帐户不仅仅是简单的发布商帐户,其发布商帐户嵌入了Google商家钱包帐户。详细信息可以在下面的链接中找到。

    http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113468

答案 1 :(得分:2)

有两种方式

  • 维护服务器端的数据库,并为用户+购买的产品列表+到期日创建一个表
  • 或客户端应用程序将加密代码保存在共享首选项上(因此无法轻易入侵)

Android API不会为您提供任何库存API以维持您的购买。

我使用了第二个选项。

答案 2 :(得分:2)

  

- 购买单品       store.purchase({“android.test.purchased”})

-- multi-item purchase
store.purchase( { "android.test.purchased", "android.test.canceled" } )

参考Getting Started with Android In-app Billing

此代码可能是您正在寻找的代码

答案 3 :(得分:2)

1)下载

http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-download

2)添加

http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-add-aidl

3)在你的android清单文件中添加权限

http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-permission

现在你的项目应该是这样的......

enter image description here

4)放置公钥(你可以在开发者控制台中找到它     编辑简介的底部部分)在Security.java中说     String base64EncodedPublicKey =“你的公钥在这里”

5)最后你的按钮活动应该是这样的

公共类YourActivity扩展Activity实现OnClickListener {     String issueProductId =“您的产品ID”;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.updates);
    SetInAppBilling();
    Button donate = (Button) findViewById(R.id.donate);
    donate.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            if (mBillingService.requestPurchase(issueProductId, null)) {

            } else {
                showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
                Log.i("tag", "Can't purchase on this device");

            }

        }
    });
}


public void register() {
    ResponseHandler.register(mDungeonsPurchaseObserver);
}

public void unregister() {
    ResponseHandler.unregister(mDungeonsPurchaseObserver);
}

public void close_unbind() {
    if (mPurchaseDatabase != null)
        // mPurchaseDatabase.close();
        if (mBillingService != null)
            mBillingService.unbind();
    // stopService(new Intent(this, BillingService.class));
}

/**
 * Called when this activity becomes visible.
 */
@Override
protected void onStart() {
    super.onStart();

    register();
}

/**
 * Called when this activity is no longer visible.
 */
@Override
protected void onStop() {
    unregister();
    super.onStop();

}

@Override
protected void onDestroy() {
    close_unbind();
    super.onDestroy();

}

private static final String TAG = "YourActivity";

private static final String DB_INITIALIZED = "db_initialized";

// private static final String Dir_Check = "Dir_Check";

private DungeonsPurchaseObserver mDungeonsPurchaseObserver;
private Handler mHandler;

private BillingService mBillingService;
private PurchaseDatabase mPurchaseDatabase;
private static final int DIALOG_CANNOT_CONNECT_ID = 1;
private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2;
private Cursor mOwnedItemsCursor;

public void SetInAppBilling() {
    mHandler = new Handler();
    mDungeonsPurchaseObserver = new DungeonsPurchaseObserver(mHandler);
    mBillingService = new BillingService();
    mBillingService.setContext(this);

    mPurchaseDatabase = new PurchaseDatabase(this);

    mOwnedItemsCursor = mPurchaseDatabase
            .queryAllPurchasedHistroyTabelItems();
    startManagingCursor(mOwnedItemsCursor);

    SharedPreferences prefs = getPreferences(MODE_PRIVATE);
    boolean initialized = prefs.getBoolean(DB_INITIALIZED, false);
    // Check if billing is supported.
    ResponseHandler.register(mDungeonsPurchaseObserver);
    if (!mBillingService.checkBillingSupported()) {
        showDialog(DIALOG_CANNOT_CONNECT_ID);
    }
}

private class DungeonsPurchaseObserver extends PurchaseObserver {
    public DungeonsPurchaseObserver(Handler handler) {
        super(YourActiviy.this, handler);
    }

    @Override
    public void onBillingSupported(boolean supported) {

        Log.i(TAG, "supportedCheck: " + supported);
        if (Consts.DEBUG) {
            Log.i(TAG, "supported: " + supported);
        }
        if (supported) {
            restoreDatabase();
        } else {
            showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
        }
    }

    @Override
    public void onPurchaseStateChange(PurchaseState purchaseState,
            String itemId, int quantity, long purchaseTime,
            String developerPayload) {
        if (Consts.DEBUG) {
            Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " "
                    + purchaseState);
        }

        if (developerPayload == null) {

        } else {

        }

        Log.e(TAG, "onPurchaseStateChangeCheck: " + "onPurchaseStateChange");
        if (purchaseState == PurchaseState.PURCHASED) {

            /** TODO: */
            Toast.makeText(
                    mContext,
                    "You successfully upgraded to the entire Volume One. Enjoy!",
                    Toast.LENGTH_SHORT).show();
            finish();
        }

    }

    @Override
    public void onRequestPurchaseResponse(RequestPurchase request,
            ResponseCode responseCode) {
        if (Consts.DEBUG) {
            Log.d(TAG, request.mProductId + ": " + responseCode);
        }
        if (responseCode == ResponseCode.RESULT_OK) {
            if (Consts.DEBUG) {
                Log.i(TAG, "purchase was successfully sent to server");
            }

        } else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
            if (Consts.DEBUG) {
                Log.i(TAG, "user canceled purchase");
            }

        } else {
            if (Consts.DEBUG) {
                Log.i(TAG, "purchase failed");
            }

        }
    }

    @Override
    public void onRestoreTransactionsResponse(RestoreTransactions request,
            ResponseCode responseCode) {
        if (responseCode == ResponseCode.RESULT_OK) {
            if (Consts.DEBUG) {
                Log.d(TAG, "completed RestoreTransactions request");
            }
            // Update the shared preferences so that we don't perform
            // a RestoreTransactions again.

            SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
            SharedPreferences.Editor edit = prefs.edit();
            edit.putBoolean(DB_INITIALIZED, true);
            edit.commit();

            mOwnedItemsCursor = mPurchaseDatabase
                    .queryAllPurchasedHistroyTabelItems();
            Log.d(TAG, String.valueOf(mOwnedItemsCursor.getCount()));
            startManagingCursor(mOwnedItemsCursor);

            if (mOwnedItemsCursor.getCount() > 0) {
                Log.d(TAG, "Updating the DB");
                Toast.makeText(
                        mContext,
                        "You successfully upgraded to the entire Volume One. Enjoy!",
                        Toast.LENGTH_SHORT).show();
                finish();
            }

        } else {
            if (Consts.DEBUG) {
                Log.d(TAG, "RestoreTransactions error: " + responseCode);
            }
        }
    }
}

@Override
protected Dialog onCreateDialog(int id) {
    switch (id) {
    case DIALOG_CANNOT_CONNECT_ID:
        return createDialog(R.string.cannot_connect_title,
                R.string.cannot_connect_message);
    case DIALOG_BILLING_NOT_SUPPORTED_ID:
        return createDialog(R.string.billing_not_supported_title,
                R.string.billing_not_supported_message);
    default:
        return null;
    }
}

private Dialog createDialog(int titleId, int messageId) {
    String helpUrl = replaceLanguageAndRegion(getString(R.string.help_url));
    if (Consts.DEBUG) {
        Log.i(TAG, helpUrl);
    }
    final Uri helpUri = Uri.parse(helpUrl);

    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(titleId)
            .setIcon(android.R.drawable.stat_sys_warning)
            .setMessage(messageId)
            .setCancelable(false)
            .setPositiveButton(android.R.string.ok, null)
            .setNegativeButton(R.string.learn_more,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,
                                int which) {
                            Intent intent = new Intent(Intent.ACTION_VIEW,
                                    helpUri);
                            startActivity(intent);
                        }
                    });
    return builder.create();
}

/**
 * Replaces the language and/or country of the device into the given string.
 * The pattern "%lang%" will be replaced by the device's language code and
 * the pattern "%region%" will be replaced with the device's country code.
 * 
 * @param str
 *            the string to replace the language/country within
 * @return a string containing the local language and region codes
 */
private String replaceLanguageAndRegion(String str) {
    // Substitute language and or region if present in string
    if (str.contains("%lang%") || str.contains("%region%")) {
        Locale locale = Locale.getDefault();
        str = str.replace("%lang%", locale.getLanguage().toLowerCase());
        str = str.replace("%region%", locale.getCountry().toLowerCase());
    }
    return str;
}

private void restoreDatabase() {
    SharedPreferences prefs = getPreferences(MODE_PRIVATE);
    boolean initialized = prefs.getBoolean(DB_INITIALIZED, false);
    if (!initialized) {
        mBillingService.restoreTransactions();
        // Toast.makeText(this, "restoring...", Toast.LENGTH_LONG).show();

    }
}

}

答案 4 :(得分:2)

此处我用于Simple InApp Billing / Payment的代码,您也可以使用。

enter image description here

另请参阅this code可帮助。

答案 5 :(得分:2)

来自Google的示例应用内结算代码是一个良好的开端。我已经发布了一个指向我给出的教程的链接,这是一个三部分。这个链接是三个中的第一个。我希望它有所帮助。

http://www.mobileoped.com/2012/04/06/android-google-play-in-app-billing-part-1/