在使用James Montemagno的Xamarin.Android应用内计费插件时,在尝试从Google Play购买产品时,购买屏幕上会出现模糊的错误消息:
Something went wrong on our end. Please try again
我或多或少完全使用了插件文档中的示例代码。该插件可以与用于测试的保留帐单ID配合使用,例如android.test.purchased
。该支持论坛指出,该问题是由于“现有安全措施”引起的,尚不十分清楚-https://forums.xamarin.com/discussion/153166/in-app-purchase-error-something-went-wrong-on-our-end-please-try-again。
导致的错误代码为Plugin.InAppBilling.Abstractions.PurchaseError.UserCancelled
。
以下是购买功能的代码:
class ProVersionUnlocker
{
string ProductID = "XXXXXXXXXXXX";
public async Task<bool> WasProVersionPurchased()
{
/*TESTING
*
* TESTING
*
* TESTING
*/
#if DEBUG
//return true;
#endif
var billing = CrossInAppBilling.Current;
try
{
var connected = await billing.ConnectAsync(ItemType.InAppPurchase);
if (!connected)
{
//Couldn't connect
return false;
}
//check purchases
var purchases = await billing.GetPurchasesAsync(ItemType.InAppPurchase);
//check for null just incase
if (purchases?.Any(p => p.ProductId == ProductID) ?? false)
{
//Purchase restored
return true;
}
else
{
//no purchases found
return false;
}
}
catch (InAppBillingPurchaseException purchaseEx)
{
//Billing Exception handle this based on the type
Log.Debug("IAP", "Error: " + purchaseEx);
}
catch (Exception ex)
{
//Something has gone wrong
}
finally
{
await billing.DisconnectAsync();
}
return false;
}
public async Task<bool> PurchaseProVersion()
{
if (await WasProVersionPurchased())
return true;
string Payload = "ProVersionProVersion";
var billing = CrossInAppBilling.Current;
try
{
var connected = await billing.ConnectAsync(ItemType.InAppPurchase);
if (!connected)
{
//we are offline or can't connect, don't try to purchase
return false;
}
//check purchases
var purchase = await billing.PurchaseAsync(ProductID, ItemType.InAppPurchase, Payload, new Verify());
//Consume for further testing
//var consumedItem = await CrossInAppBilling.Current.ConsumePurchaseAsync(purchase.ProductId, purchase.PurchaseToken);
//possibility that a null came through.
if (purchase == null)
{
//did not purchase; do nothing and fall through to failure
}
else if (purchase.State == PurchaseState.Purchased)
{
return true;
}
}
catch (InAppBillingPurchaseException purchaseEx)
{
//Billing Exception handle this based on the type
//Maybe it was an Already Purchased Error, in which case we return true
if (purchaseEx.PurchaseError == PurchaseError.AlreadyOwned)
return true;
Log.Debug("IAP", "Error: " + purchaseEx);
}
catch (Exception ex)
{
//Something else has gone wrong, log it
Log.Debug("IAP", "Issue connecting: " + ex);
}
finally
{
await billing.DisconnectAsync();
}
return false;
}
public class Verify : IInAppBillingVerifyPurchase
{
const string key1 = @"XOR_key1";
const string key2 = @"XOR_key2";
const string key3 = @"XOR_key3";
public Task<bool> VerifyPurchase(string signedData, string signature, string productId = null, string transactionId = null)
{
//This is only used for testing things at the moment.
#if false
var key1Transform = Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.TransformString(key1, 1);
var key2Transform = Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.TransformString(key2, 2);
var key3Transform = Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.TransformString(key3, 3);
return Task.FromResult(Plugin.InAppBilling.InAppBillingImplementation.InAppBillingSecurity.VerifyPurchase(key1Transform + key2Transform + key3Transform, signedData, signature));
#else
return Task.FromResult(true);
#endif
}
}
这是调用代码,它位于PreferenceFragment中:
var Unlocker = new ProVersionUnlocker();
var unlock = this.FindPreference("unlock");
unlock.PreferenceClick += async (sender, e) =>
{
//Toast.MakeText(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity, "Ayy lmao", ToastLength.Short).Show();
unlock.SetSummary(Resource.String.PressAgain);
bool Success = await Unlocker.PurchaseProVersion();
//Toast.MakeText(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity, Success.ToString(), ToastLength.Short).Show();
UnlockStuff();
};