Example #1
0
		/// <summary>
		/// Handles an activity result that's part of the purchase flow in in-app billing. If you
		/// are calling <seealso cref="#launchPurchaseFlow"/>, then you must call this method from your
		/// Activity's <seealso cref="android.app.Activity@onActivityResult"/> method. This method
		/// MUST be called from the UI thread of the Activity.
		/// </summary>
		/// <param name="requestCode"> The requestCode as you received it. </param>
		/// <param name="resultCode"> The resultCode as you received it. </param>
		/// <param name="data"> The data (Intent) as you received it. </param>
		/// <returns> Returns true if the result was related to a purchase flow and was handled;
		///     false if the result was not related to a purchase, in which case you should
		///     handle it normally. </returns>
		public bool handleActivityResult(int requestCode, int resultCode, Intent data)
		{
			IabResult result;
			if (requestCode != mRequestCode)
			{
				return false;
			}

			checkNotDisposed();
			checkSetupDone("handleActivityResult");

			// end of async purchase operation that started on launchPurchaseFlow
			flagEndAsync();

			if (data == null)
			{
				logError("Null data in IAB activity result.");
				result = new IabResult(IABHELPER_BAD_RESPONSE, "Null data in IAB result");
				if (mPurchaseListener != null)
				{
					mPurchaseListener.onIabPurchaseFinished(result, null);
				}
				return true;
			}

			int responseCode = getResponseCodeFromIntent(data);
			string purchaseData = data.GetStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
			string dataSignature = data.GetStringExtra(RESPONSE_INAPP_SIGNATURE);

			if (resultCode == (int)Result.Ok && responseCode == BILLING_RESPONSE_RESULT_OK)
			{
				logDebug("Successful resultcode from purchase activity.");
				logDebug("Purchase data: " + purchaseData);
				logDebug("Data signature: " + dataSignature);
				logDebug("Extras: " + data.Extras);
				logDebug("Expected item type: " + mPurchasingItemType);

				if (purchaseData == null || dataSignature == null)
				{
					logError("BUG: either purchaseData or dataSignature is null.");
					logDebug("Extras: " + data.Extras.ToString());
					result = new IabResult(IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature");
					if (mPurchaseListener != null)
					{
						mPurchaseListener.onIabPurchaseFinished(result, null);
					}
					return true;
				}

				Purchase purchase = null;
				try
				{
					purchase = new Purchase(mPurchasingItemType, purchaseData, dataSignature);
					string sku = purchase.Sku;

					// Verify signature
					if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature))
					{
						logError("Purchase signature verification FAILED for sku " + sku);
						result = new IabResult(IABHELPER_VERIFICATION_FAILED, "Signature verification failed for sku " + sku);
						if (mPurchaseListener != null)
						{
							mPurchaseListener.onIabPurchaseFinished(result, purchase);
						}
						return true;
					}
					logDebug("Purchase signature successfully verified.");
				}
				catch (JSONException e)
				{
					logError("Failed to parse purchase data.");
					Console.WriteLine(e.ToString());
					Console.Write(e.StackTrace);
					result = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data.");
					if (mPurchaseListener != null)
					{
						mPurchaseListener.onIabPurchaseFinished(result, null);
					}
					return true;
				}

				if (mPurchaseListener != null)
				{
					mPurchaseListener.onIabPurchaseFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase);
				}
			}
			else if (resultCode == (int)Result.Ok)
			{
				// result code was OK, but in-app billing response was not OK.
				logDebug("Result code was OK but in-app billing response was not OK: " + getResponseDesc(responseCode));
				if (mPurchaseListener != null)
				{
					result = new IabResult(responseCode, "Problem purchashing item.");
					mPurchaseListener.onIabPurchaseFinished(result, null);
				}
			}
            else if (resultCode == (int)Result.Canceled)
			{
				logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
				result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled.");
				if (mPurchaseListener != null)
				{
					mPurchaseListener.onIabPurchaseFinished(result, null);
				}
			}
			else
			{
				logError("Purchase failed. Result code: " + Convert.ToString(resultCode) + ". Response: " + getResponseDesc(responseCode));
				result = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response.");
				if (mPurchaseListener != null)
				{
					mPurchaseListener.onIabPurchaseFinished(result, null);
				}
			}
			return true;
		}
Example #2
0
				public RunnableAnonymousInnerClassHelper2(RunnableAnonymousInnerClassHelper outerInstance, IabResult result_f, Inventory inv_f)
				{
					this.outerInstance = outerInstance;
					this.result_f = result_f;
					this.inv_f = inv_f;
				}
Example #3
0
		/// <summary>
		/// Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase,
		/// which will involve bringing up the Google Play screen. The calling activity will be paused while
		/// the user interacts with Google Play, and the result will be delivered via the activity's
		/// <seealso cref="android.app.Activity#onActivityResult"/> method, at which point you must call
		/// this object's <seealso cref="#handleActivityResult"/> method to continue the purchase flow. This method
		/// MUST be called from the UI thread of the Activity.
		/// </summary>
		/// <param name="act"> The calling activity. </param>
		/// <param name="sku"> The sku of the item to purchase. </param>
		/// <param name="itemType"> indicates if it's a product or a subscription (ITEM_TYPE_INAPP or ITEM_TYPE_SUBS) </param>
		/// <param name="requestCode"> A request code (to differentiate from other responses --
		///     as in <seealso cref="android.app.Activity#startActivityForResult"/>). </param>
		/// <param name="listener"> The listener to notify when the purchase process finishes </param>
		/// <param name="extraData"> Extra data (developer payload), which will be returned with the purchase data
		///     when the purchase completes. This extra data will be permanently bound to that purchase
		///     and will always be returned when the purchase is queried. </param>
		public void launchPurchaseFlow(Activity act, string sku, string itemType, int requestCode, OnIabPurchaseFinishedListener listener, string extraData)
		{
			checkNotDisposed();
			checkSetupDone("launchPurchaseFlow");
			flagStartAsync("launchPurchaseFlow");
			IabResult result;

			if (itemType.Equals(ITEM_TYPE_SUBS) && !mSubscriptionsSupported)
			{
				IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, "Subscriptions are not available.");
				flagEndAsync();
				if (listener != null)
				{
					listener.onIabPurchaseFinished(r, null);
				}
				return;
			}

			try
			{
				logDebug("Constructing buy intent for " + sku + ", item type: " + itemType);
				Bundle buyIntentBundle = mService.GetBuyIntent(3, mContext.PackageName, sku, itemType, extraData);
				int response = getResponseCodeFromBundle(buyIntentBundle);
				if (response != BILLING_RESPONSE_RESULT_OK)
				{
					logError("Unable to buy item, Error response: " + getResponseDesc(response));
					flagEndAsync();
					result = new IabResult(response, "Unable to buy item");
					if (listener != null)
					{
						listener.onIabPurchaseFinished(result, null);
					}
					return;
				}

				PendingIntent pendingIntent = (PendingIntent)buyIntentBundle.GetParcelable(RESPONSE_BUY_INTENT);
				logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode);
				mRequestCode = requestCode;
				mPurchaseListener = listener;
				mPurchasingItemType = itemType;
                act.StartIntentSenderForResult(pendingIntent.IntentSender, requestCode, new Intent(), ActivityFlags.BroughtToFront, ActivityFlags.BroughtToFront, Convert.ToInt32(0));
			}
			catch (Android.Content.IntentSender.SendIntentException e)
			{
				logError("SendIntentException while launching purchase flow for sku " + sku);
				Console.WriteLine(e.ToString());
				Console.Write(e.StackTrace);
				flagEndAsync();

				result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent.");
				if (listener != null)
				{
					listener.onIabPurchaseFinished(result, null);
				}
			}
			catch (RemoteException e)
			{
				logError("RemoteException while launching purchase flow for sku " + sku);
				Console.WriteLine(e.ToString());
				Console.Write(e.StackTrace);
				flagEndAsync();

				result = new IabResult(IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow");
				if (listener != null)
				{
					listener.onIabPurchaseFinished(result, null);
				}
			}
		}