Android 使用OpenIAB提交到Amazon Appstore
我们在第一个Android应用程序中使用OpenIAB进行应用内购买。我们设置了所有内容,并能够使用Amazon App Tester在设备上成功测试,并使用终端中的./adb install-i com.Amazon.venezia appname.apk命令安装应用程序 然而,当我们提交给亚马逊应用商店时,他们的测试人员拒绝了我们,因为该应用不会下载应用内购买/价格。我要说的是,它在使用OpenIAB的GooglePlay中也运行得非常好 我已经包含了我们在下面编写的代码。我们还按照网站的建议设置了manifest和proguard-rules.pro。我们将非常感谢您的任何帮助,因为我们没有得到亚马逊的支持:Android 使用OpenIAB提交到Amazon Appstore,android,in-app-purchase,amazon,Android,In App Purchase,Amazon,我们在第一个Android应用程序中使用OpenIAB进行应用内购买。我们设置了所有内容,并能够使用Amazon App Tester在设备上成功测试,并使用终端中的./adb install-i com.Amazon.venezia appname.apk命令安装应用程序 然而,当我们提交给亚马逊应用商店时,他们的测试人员拒绝了我们,因为该应用不会下载应用内购买/价格。我要说的是,它在使用OpenIAB的GooglePlay中也运行得非常好 我已经包含了我们在下面编写的代码。我们还按照网站的建
public class InAppBilling {
private static final String TAG = "InAppBilling";
private static InAppBilling mInstance = null;
// (arbitrary) request code for the purchase flow
static final int RC_REQUEST = <number goes here>;
private OpenIabHelper mHelper;
private NoteListFragment mFragment;
private Context mContext;
private InAppBilling() {}
public static InAppBilling get() {
if (mInstance == null) {
InAppConfig.init();
mInstance = new InAppBilling();
}
return mInstance;
}
public OpenIabHelper getHelper() {
return mHelper;
}
// Initialize OpenIAB library and when completed automatically kick off full product info download
public void init(Context context, NoteListFragment fragment) {
mContext = context;
// If library was already initialized, go straight to info download, don't init twice
if (mHelper != null) {
InAppBilling.get().queryPricesAndPurchases(fragment);
return;
}
// Create the helper, passing it our context and the public keys to verify signatures with
//Log.d(TAG, "Creating IAB helper.");
OpenIabHelper.Options.Builder builder = new OpenIabHelper.Options.Builder()
.setStoreSearchStrategy(OpenIabHelper.Options.SEARCH_STRATEGY_INSTALLER_THEN_BEST_FIT)
.setVerifyMode(OpenIabHelper.Options.VERIFY_EVERYTHING)
.addStoreKeys(InAppConfig.STORE_KEYS_MAP);
mHelper = new OpenIabHelper(context, builder.build());
// enable debug logging (for a production application, you should comment this out)
//OpenIabHelper.enableDebugLogging(true);
// Start setup. This is asynchronous and the embedded listener
// will be called once setup completes.
//Log.d(TAG, "Starting IAB setup.");
mFragment = fragment; // cache for use by callback
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
//Log.d(TAG, "IAB Setup finished.");
if (!result.isSuccess()) {
//Log.d(TAG, "Problem setting up in-app billing: " + result);
mHelper = null;
return;
}
//Log.d(TAG, "IAB Setup successful.");
InAppBilling.get().queryPricesAndPurchases(null); // use cached mFragment
}
});
}
// Launches a background download of info for all products
public void queryPricesAndPurchases(NoteListFragment fragment) {
if (fragment != null)
mFragment = fragment;
//Log.d(TAG, "Launching product info query");
mHelper.queryInventoryAsync(true, InAppConfig.ALL_SKUS, mGotInventoryListener);
}
// Listener that's called when we finish querying the product info
// Sets the price info for all packs, and clears and then re-sets the notes' purchased states
private IabHelper.QueryInventoryFinishedListener mGotInventoryListener =
new IabHelper.QueryInventoryFinishedListener() {
@Override
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
//Log.d(TAG, "Query inventory finished: " + inventory.getAllPurchases() + inventory.getAllOwnedSkus());
if (result.isFailure()) {
//Log.d(TAG, "Failed to query inventory: " + result);
return;
}
//Log.d(TAG, "Query inventory was successful.");
// Note & pack data controller singletons already exist (created at startup)
// so we don't need to pass a Context here (which we don't really have handy)
PackDataController pdc = PackDataController.get(null);
NoteDataController ndc = NoteDataController.get(null);
ndc.returnAllNotes();
for (String sku : InAppConfig.ALL_SKUS) {
Pack pack = pdc.findPackWithAppStoreId(sku);
if (pack != null) {
if (inventory.hasDetails(sku)) {
SkuDetails details = inventory.getSkuDetails(sku);
String price = details.getPrice();
pack.setPrice(price); // supposedly localized according to user's account
//Log.d(TAG, "SKU " + sku + " = " + price);
} else {
//Log.d(TAG, "SKU " + sku + " details not found");
}
if (inventory.hasPurchase(sku)) {
Purchase purchase = inventory.getPurchase(sku);
if (verifyDeveloperPayload(purchase)) {
//Log.d(TAG, "Purchased SKU " + sku);
ndc.purchaseNotesWithPackId(pack.getId(), true);
} else {
//Log.d(TAG, "Payload verification failed SKU " + sku);
}
}
}
}
ndc.updateNoteList();
mFragment.updateNoteAdapter();
}
};
/**
* Verifies the developer payload of a purchase.
*/
boolean verifyDeveloperPayload(Purchase p) {
String store = mHelper.getConnectedAppstoreName();
if (store != null && store.equals(OpenIabHelper.NAME_AMAZON))
return true; // Amazon doesn't support payload verification, so bypass it
if (p == null || p.getSku() == null)
return false;
String payload = p.getDeveloperPayload();
if (payload == null)
return false;
return payload.equals(p.getSku() + p.getSku().length() * 13);
}
// Launches a product purchase request in a background thread
public void purchase(Activity act, String sku) {
if (!sku.contains("."))
sku = InAppConfig.SKU_PREFIX + sku;
String payload = sku + sku.length() * 13;
mHelper.launchPurchaseFlow(act, sku, RC_REQUEST, mPurchaseFinishedListener, payload);
}
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
//Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
if (result.isFailure()) {
//Log.d(TAG, "Error purchasing: " + result);
return;
}
if (!verifyDeveloperPayload(purchase)) {
//Log.d(TAG, "Error purchasing. Authenticity verification failed.");
return;
}
//Log.d(TAG, "Purchase successful: " + purchase.getAppstoreName() + ", SKU: " + purchase.getSku());
PackDataController pdc = PackDataController.get(null);
Pack pack = pdc.findPackWithAppStoreId(purchase.getSku());
NoteDataController ndc = NoteDataController.get(null);
ndc.purchaseNotesWithPackId(pack.getId(), true);
ndc.updateNoteList();
if (mFragment != null)
mFragment.updateNoteAdapter();
Intent intent = new Intent("purchase-completed");
// You can also include some extra data.
intent.putExtra("message", "Purchase completed, reload template");
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}
};
}
应用计费中的公共类{
私有静态最终字符串TAG=“InAppBilling”;
私有静态不适用实例=null;
//(任意)采购流程的请求代码
静态最终int RC_请求=;
私人开放式酒店;
私人票据碎片;
私有上下文;
私有InAppBilling(){}
公共静态InAppGet(){
if(minInstance==null){
InAppConfig.init();
MinInstance=新的不适用计费();
}
回报率;
}
公共OpenHelper getHelper(){
返回mHelper;
}
//初始化OpenIAB库,完成后自动启动完整的产品信息下载
公共void init(上下文,NoteListFragment片段){
mContext=上下文;
//若库已经初始化,直接转到信息下载,不要初始化两次
如果(mHelper!=null){
InAppBilling.get().queryPricesAndPurchases(片段);
回来
}
//创建助手,将上下文和公钥传递给它以验证签名
//Log.d(标记“创建IAB助手”);
OpenIabHelper.Options.Builder=new OpenIabHelper.Options.Builder()
.setStoreSearchStrategy(OpenIabHelper.Options.SEARCH\u STRATEGY\u INSTALLER\u然后\u BEST\u FIT)
.setVerifyMode(OpenIabHelper.Options.VERIFY\u所有内容)
.addStoreKeys(InAppConfig.STORE\u KEYS\u MAP);
mHelper=newOpenIbaHelper(上下文,builder.build());
//启用调试日志记录(对于生产应用程序,您应该对此进行注释)
//OpenIbaHelper.enableDebugLogging(true);
//启动安装程序。这是异步的,并且是嵌入式侦听器
//安装程序完成后将调用。
//Log.d(标签“启动IAB设置”);
mffragment=fragment;//用于回调的缓存
mHelper.startSetup(新的IabHelper.OnIabSetupFinishedListener(){
已完成公共void ONIBS设置(IAB结果){
//Log.d(标记“IAB设置完成”);
如果(!result.issucess()){
//Log.d(标签,“应用内计费设置问题:+结果”);
mHelper=null;
回来
}
//Log.d(标记“IAB设置成功”);
InAppBilling.get().queryPricesAndPurchases(null);//使用缓存的MFFragment
}
});
}
//启动所有产品的后台信息下载
公共无效查询价格和购买(NoteListFragment片段){
if(片段!=null)
mFragment=片段;
//Log.d(标签“启动产品信息查询”);
mHelper.queryInventoryAsync(true,在appconfig.ALL_SKU中,mGotInventoryListener);
}
//完成查询产品信息时调用的侦听器
//设置所有包装的价格信息,清除并重新设置票据的购买状态
私有IabHelper.QueryInventoryFinishedListener管理InventoryListener=
新建IabHelper.QueryInventoryFinishedListener(){
@凌驾
QueryInventoryFinished上的公共无效(IABREACT结果,库存){
//Log.d(标记“查询库存完成:”+inventory.getAllPurchases()+inventory.getAllowedskus());
if(result.isFailure()){
//Log.d(标记“无法查询库存:+结果”);
回来
}
//Log.d(标记“查询库存成功”);
//注意&包数据控制器单例已存在(在启动时创建)
//因此,我们不需要在这里传递上下文(实际上我们手头没有上下文)
PackDataController pdc=PackDataController.get(null);
NoteDataController ndc=NoteDataController.get(null);
ndc.returnAllNotes();
用于(字符串sku:InAppConfig.ALL_sku){
Pack Pack=pdc.findPackWithAppStoreId(sku);
if(pack!=null){
if(库存详细信息(sku)){
SkuDetails details=存货。获取sku详细信息(sku);
字符串price=details.getPrice();
pack.setPrice(price);//应该根据用户的帐户进行本地化
//Log.d(标签,“SKU”+SKU+“=”+价格);
}否则{
//Log.d(标记“SKU”+SKU+“未找到详细信息”);
}
if(库存、采购(sku)){
采购=存货.getPurchase(sku);
if(验证developerPayLoad(购买)){
//日志d(标签“购买的SKU”+SKU);
ndc.purchaseNotesWithPackId(pack.getId(),true);
}否则{
//Log.d(标签“有效负载验证失败的SKU”+SKU);
}
}
}
}
ndc.updateNotList();
mFragment.UpdateNodeAdapter();
}
};
/**
*验证购买的开发人员有效负载。
*/
布尔验证developerPayLoad(购买p){
字符串存储=mHelper.getConnecte