I am a novice Android developer who has never used in-app billing before. So I have followed the steps outlined in Google's own documentation at http://developer.android.com/google/play/billing/billing_integrate.html.
I added the IInAppBillingService.aidl file under main/aidl/com.android.vending.billing and my structure matches countless screenshots I've seen online.
I added code very similar to the sample code to a part of my app that interacts with my online marketplace. A simplified version of that code, with extraneous stuff removed, is:
imports...
import android.content.ServiceConnection;
import com.android.vending.billing.IInAppBillingService;
public class intMarket extends Activity {
IInAppBillingService mService;
public static final String SHARED_PREFS_NAME="myAppSettings";
public static String purchaseToken = "";
ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name,
IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intbrowser);
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(new WebAppInterface(this), "Android");
String tUrl = getString(R.string.urlMarket);
SharedPreferences settings = getSharedPreferences(SHARED_PREFS_NAME, 0);
myWebView.loadUrl(tUrl);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mService != null) {
unbindService(mServiceConn);
}
}
@Override
protected void 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 = new JSONObject(purchaseData);
String sku = jo.getString("productId");
purchaseToken = jo.getString("purchaseToken");
}
catch (JSONException e) {
e.printStackTrace();
}
}
}
}
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public void purchaseItem(Integer itemID, String itemName, BigDecimal itemPrice) {
// Credit Purchase
ArrayList<String> skuList = new ArrayList<String> ();
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
String purchaseCreditsResponse = "Success";
try {
Bundle skuDetails = mService.(3, getPackageName(), "inapp", querySkus);
Log.d("WPS", skuDetails.toString());
int response = skuDetails.getInt("RESPONSE_CODE");
Log.d("WPS", Integer.toString(response));
if (response == 0) {
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
String thisItemID = "0";
for (String thisResponse : responseList) {
JSONObject object = new JSONObject(thisResponse);
String itemPrice = object.getString("price");
if (itemPrice.equals(itemPrice.toString()))
thisItemID = object.getString("productId");
}
if (Integer.parseInt(thisItemID) > 0) {
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), thisItemID, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
if (buyIntentBundle.getInt("RESPONSE_CODE") == 0) {
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
//startIntentSenderForResult(pendingIntent.getIntentSender(), 1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
// purchaseToken
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Buying: " + itemName, Toast.LENGTH_LONG).show();
}
} else {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 001.", Toast.LENGTH_LONG).show();
}
} else {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 002.", Toast.LENGTH_LONG).show();
}
} catch (RemoteException e) {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 003.", Toast.LENGTH_LONG).show();
} catch (JSONException e) {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 004.", Toast.LENGTH_LONG).show();
}// catch (IntentSender.SendIntentException e) {
// purchaseCreditsResponse = "Failure";
// Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 005.", Toast.LENGTH_LONG).show();
//}
// Purchase Report
// Report purchase and get response into purchaseResponse
// Todo
// Credit Consumption
// Todo
}
}
}
I then compiled a version of this and uploaded the APK to Google Play as an alpha test case and published it. I have been making updates and using ADB to install the new compiled APKs to my phone, but I continually get the following from this code in LogCat:
03-23 15:07:55.325 2958-3009/? D/WPS﹕ Bundle[mParcelledData.dataSize=48]
03-23 15:07:55.325 2958-3009/? D/WPS﹕ 5
Which, of course, indicates: BILLING_RESPONSE_RESULT_DEVELOPER_ERROR
I read in another SO post that you cannot test billing on a device whose main account is the same as the developer's account. So I spent several hours yesterday tracking down another phone and getting it setup using a completely separate account (and the only account on the device). I uploaded a new build to Google Play as an alpha test and published it. I waited for this other phone to get the new version and tried testing billing again. The phone reported this error message that I had built in:
Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 002.
Which indicates the same error I was running into before. This implies that there is a problem with my code, which would not surprise me.
I have not done anything with the big giant license code that appears in the Google Play developer panel because the above referenced documentation says nothing about it being required. But is it? If not, what about my code is causing this problem?