Intereting Posts
Ошибка: ожидаемый ресурс типа styleable error В чем разница между onCreateOptionsMenu (меню меню) и onPrepareOptionsMenu (меню меню)? Доступ к определенной загруженной базе данных .sqlite во внешнем хранилище из приложения для Android Используйте камеру, подключенную через USB вместо встроенной камеры Android ActionBar скрыть / показать при просмотре списка прокрутки Android включает и выключает Wi-Fi HotSpot программно Как определить, разрушается ли родительская активность вида Тип Несоответствие типа: невозможно преобразовать из RegisterFragment в Fragment Это хорошая идея написать мобильные игры в ActionScript3, а не Java / Objective-C? Доступ к ресурсам контрольно-измерительных приборов Включая приложение QR-сканера с PhoneGap Цель описанияСодержание () Parcelable interface Android EditText maxLength не работает ERROR: папка SWT '' не существует. Пожалуйста, установите ANDROID_SWT .. a получите эту ошибку после обновления SDK У устройств Android 4.x есть сообщения GCM, но устройства Android 2.3 Do not

In-App-Billing – BillingHelper полностью не создан

Что я пытаюсь сделать


Привет, ребята, я пытаюсь создать некоторые In-App-продукты для своего приложения, для использования пожертвований. Потому что я отдаю свободный musik моего друга – он рвется. Независимо от того, я создал 5 продуктов In-App на моей учетной записи разработчика:

  • donate_small
  • donate_midsmall
  • donate_medium
  • donate_large
  • donate_xlarge

Это ссылочный ключ, который я создал там. Они сохраняются и публикуются. Теперь, если вы написали In-App-Service по этому руководству: In-App Easy Tutorial . Код, кажется, работает отлично, ошибок нет, и когда я скомпилирую демо-код, он работает. Но когда я пытаюсь, я получаю всю эту ошибку:

12-06 14:23:49.400: E/BillingService(4719): BillingHelper not fully instantiated 

Вопрос


Итак, что мне нужно для изменения, пользователь может выбрать разные приложения в приложении? Мне нужно объявить их где-нибудь? Также, если у вас есть отличный учебник для меня, где все это хорошо описано и полностью работает, пожалуйста, скажите мне.

Это классы, которые я использую для своего In-App-сервиса:

de.stepforward

  • ChannelActivity
  • SplashActivity

de.stepforward.billing

  • AppMainTest.class -> Это моя деятельность
  • BillingHelper.class
  • BillingReceiver.class
  • BillingSecurity.class
  • BillingService.class
  • C.class

de.stepforward.billing.util

  • Base64.class
  • Base64DecoderException.class

На данный момент я дам вам код моего BillingHelper и Activity, если вам нужно больше кода, просто скажите мне.

Код


AppMainTest.class

 package de.stepforward.billing; import de.stepforward.R; import de.stepforward.R.id; import de.stepforward.R.layout; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; public class AppMainTest extends Activity implements OnClickListener{ private static final String TAG = "BillingService"; private Context mContext; private ImageView purchaseableItem; private Button purchaseButton; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i("BillingService", "Starting"); setContentView(R.layout.donate); mContext = this; purchaseButton = (Button) findViewById(R.id.main_purchase_yes); purchaseButton.setOnClickListener(this); purchaseableItem = (ImageView) findViewById(R.id.main_purchase_item); startService(new Intent(mContext, BillingService.class)); BillingHelper.setCompletedHandler(mTransactionHandler); } 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()){ showItem(); } }; }; public void onClick(View v) { switch (v.getId()) { case R.id.main_purchase_yes: if(BillingHelper.isBillingSupported()){ BillingHelper.requestPurchase(mContext, "android.test.purchased"); // android.test.purchased or android.test.canceled or android.test.refunded or com.blundell.item.passport } else { Log.i(TAG,"Can't purchase on this device"); purchaseButton.setEnabled(false); // XXX press button before service started will disable when it shouldnt } break; default: // nada Log.i(TAG,"default. ID: "+v.getId()); break; } } private void showItem() { purchaseableItem.setVisibility(View.VISIBLE); } @Override protected void onPause() { Log.i(TAG, "onPause())"); super.onPause(); } @Override protected void onDestroy() { BillingHelper.stopService(); super.onDestroy(); } } 

BillingHelper.class

 package de.stepforward.billing; import java.util.ArrayList; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.util.Log; import com.android.vending.billing.IMarketBillingService; import de.stepforward.billing.BillingSecurity.VerifiedPurchase; import de.stepforward.billing.C.ResponseCode; public class BillingHelper { private static final String TAG = "BillingService"; private static IMarketBillingService mService; private static Context mContext; private static Handler mCompletedHandler; protected static VerifiedPurchase latestPurchase; protected static void instantiateHelper(Context context, IMarketBillingService service) { mService = service; mContext = context; } protected static void setCompletedHandler(Handler handler){ mCompletedHandler = handler; } protected static boolean isBillingSupported() { if (amIDead()) { return false; } Bundle request = makeRequestBundle("CHECK_BILLING_SUPPORTED"); if (mService != null) { try { Bundle response = mService.sendBillingRequest(request); ResponseCode code = ResponseCode.valueOf((Integer) response.get("RESPONSE_CODE")); Log.i(TAG, "isBillingSupported response was: " + code.toString()); if (ResponseCode.RESULT_OK.equals(code)) { return true; } else { return false; } } catch (RemoteException e) { Log.e(TAG, "isBillingSupported response was: RemoteException", e); return false; } } else { Log.i(TAG, "isBillingSupported response was: BillingService.mService = null"); return false; } } /** * A REQUEST_PURCHASE request also triggers two asynchronous responses (broadcast intents). * First, the Android Market application sends a RESPONSE_CODE broadcast intent, which provides error information about the request. (which I ignore) * Next, if the request was successful, the Android Market application sends an IN_APP_NOTIFY broadcast intent. * This message contains a notification ID, which you can use to retrieve the transaction details for the REQUEST_PURCHASE * @param activityContext * @param itemId */ protected static void requestPurchase(Context activityContext, String itemId){ if (amIDead()) { return; } Log.i(TAG, "requestPurchase()"); Bundle request = makeRequestBundle("REQUEST_PURCHASE"); request.putString("ITEM_ID", itemId); try { Bundle response = mService.sendBillingRequest(request); //The RESPONSE_CODE key provides you with the status of the request Integer responseCodeIndex = (Integer) response.get("RESPONSE_CODE"); //The PURCHASE_INTENT key provides you with a PendingIntent, which you can use to launch the checkout UI PendingIntent pendingIntent = (PendingIntent) response.get("PURCHASE_INTENT"); //The REQUEST_ID key provides you with a unique request identifier for the request Long requestIndentifier = (Long) response.get("REQUEST_ID"); Log.i(TAG, "current request is:" + requestIndentifier); C.ResponseCode responseCode = C.ResponseCode.valueOf(responseCodeIndex); Log.i(TAG, "REQUEST_PURCHASE Sync Response code: "+responseCode.toString()); startBuyPageActivity(pendingIntent, new Intent(), activityContext); } catch (RemoteException e) { Log.e(TAG, "Failed, internet error maybe", e); Log.e(TAG, "Billing supported: "+isBillingSupported()); } } /** * A GET_PURCHASE_INFORMATION request also triggers two asynchronous responses (broadcast intents). * First, the Android Market application sends a RESPONSE_CODE broadcast intent, which provides status and error information about the request. (which I ignore) * Next, if the request was successful, the Android Market application sends a PURCHASE_STATE_CHANGED broadcast intent. * This message contains detailed transaction information. * The transaction information is contained in a signed JSON string (unencrypted). * The message includes the signature so you can verify the integrity of the signed string * @param notifyIds */ protected static void getPurchaseInformation(String[] notifyIds){ if (amIDead()) { return; } Log.i(TAG, "getPurchaseInformation()"); Bundle request = makeRequestBundle("GET_PURCHASE_INFORMATION"); // The REQUEST_NONCE key contains a cryptographically secure nonce (number used once) that you must generate. // The Android Market application returns this nonce with the PURCHASE_STATE_CHANGED broadcast intent so you can verify the integrity of the transaction information. request.putLong("NONCE", BillingSecurity.generateNonce()); // The NOTIFY_IDS key contains an array of notification IDs, which you received in the IN_APP_NOTIFY broadcast intent. request.putStringArray("NOTIFY_IDS", notifyIds); try { Bundle response = mService.sendBillingRequest(request); //The REQUEST_ID key provides you with a unique request identifier for the request Long requestIndentifier = (Long) response.get("REQUEST_ID"); Log.i(TAG, "current request is:" + requestIndentifier); //The RESPONSE_CODE key provides you with the status of the request Integer responseCodeIndex = (Integer) response.get("RESPONSE_CODE"); C.ResponseCode responseCode = C.ResponseCode.valueOf(responseCodeIndex); Log.i(TAG, "GET_PURCHASE_INFORMATION Sync Response code: "+responseCode.toString()); } catch (RemoteException e) { Log.e(TAG, "Failed, internet error maybe", e); Log.e(TAG, "Billing supported: "+isBillingSupported()); } } /** * To acknowledge that you received transaction information you send a * CONFIRM_NOTIFICATIONS request. * * A CONFIRM_NOTIFICATIONS request triggers a single asynchronous response—a RESPONSE_CODE broadcast intent. * This broadcast intent provides status and error information about the request. * * Note: As a best practice, you should not send a CONFIRM_NOTIFICATIONS request for a purchased item until you have delivered the item to the user. * This way, if your application crashes or something else prevents your application from delivering the product, * your application will still receive an IN_APP_NOTIFY broadcast intent from Android Market indicating that you need to deliver the product * @param notifyIds */ protected static void confirmTransaction(String[] notifyIds) { if (amIDead()) { return; } Log.i(TAG, "confirmTransaction()"); Bundle request = makeRequestBundle("CONFIRM_NOTIFICATIONS"); request.putStringArray("NOTIFY_IDS", notifyIds); try { Bundle response = mService.sendBillingRequest(request); //The REQUEST_ID key provides you with a unique request identifier for the request Long requestIndentifier = (Long) response.get("REQUEST_ID"); Log.i(TAG, "current request is:" + requestIndentifier); //The RESPONSE_CODE key provides you with the status of the request Integer responseCodeIndex = (Integer) response.get("RESPONSE_CODE"); C.ResponseCode responseCode = C.ResponseCode.valueOf(responseCodeIndex); Log.i(TAG, "CONFIRM_NOTIFICATIONS Sync Response code: "+responseCode.toString()); } catch (RemoteException e) { Log.e(TAG, "Failed, internet error maybe", e); Log.e(TAG, "Billing supported: " + isBillingSupported()); } } /** * * Can be used for when a user has reinstalled the app to give back prior purchases. * if an item for sale's purchase type is "managed per user account" this means google will have a record ofthis transaction * * A RESTORE_TRANSACTIONS request also triggers two asynchronous responses (broadcast intents). * First, the Android Market application sends a RESPONSE_CODE broadcast intent, which provides status and error information about the request. * Next, if the request was successful, the Android Market application sends a PURCHASE_STATE_CHANGED broadcast intent. * This message contains the detailed transaction information. The transaction information is contained in a signed JSON string (unencrypted). * The message includes the signature so you can verify the integrity of the signed string * @param nonce */ protected static void restoreTransactionInformation(Long nonce) { if (amIDead()) { return; } Log.i(TAG, "confirmTransaction()"); Bundle request = makeRequestBundle("RESTORE_TRANSACTIONS"); // The REQUEST_NONCE key contains a cryptographically secure nonce (number used once) that you must generate request.putLong("NONCE", nonce); try { Bundle response = mService.sendBillingRequest(request); //The REQUEST_ID key provides you with a unique request identifier for the request Long requestIndentifier = (Long) response.get("REQUEST_ID"); Log.i(TAG, "current request is:" + requestIndentifier); //The RESPONSE_CODE key provides you with the status of the request Integer responseCodeIndex = (Integer) response.get("RESPONSE_CODE"); C.ResponseCode responseCode = C.ResponseCode.valueOf(responseCodeIndex); Log.i(TAG, "RESTORE_TRANSACTIONS Sync Response code: "+responseCode.toString()); } catch (RemoteException e) { Log.e(TAG, "Failed, internet error maybe", e); Log.e(TAG, "Billing supported: " + isBillingSupported()); } } private static boolean amIDead() { if (mService == null || mContext == null) { Log.e(TAG, "BillingHelper not fully instantiated"); return true; } else { return false; } } private static Bundle makeRequestBundle(String method) { Bundle request = new Bundle(); request.putString("BILLING_REQUEST", method); request.putInt("API_VERSION", 1); request.putString("PACKAGE_NAME", mContext.getPackageName()); return request; } /** * * * You must launch the pending intent from an activity context and not an application context * You cannot use the singleTop launch mode to launch the pending intent * @param pendingIntent * @param intent * @param context */ private static void startBuyPageActivity(PendingIntent pendingIntent, Intent intent, Context context){ //TODO add above 2.0 implementation with reflection, for now just using 1.6 implem // This is on Android 1.6. The in-app checkout page activity will be on its // own separate activity stack instead of on the activity stack of // the application. try { pendingIntent.send(context, 0, intent); } catch (CanceledException e){ Log.e(TAG, "startBuyPageActivity CanceledException"); } } protected static void verifyPurchase(String signedData, String signature) { ArrayList<VerifiedPurchase> purchases = BillingSecurity.verifyPurchase(signedData, signature); latestPurchase = purchases.get(0); confirmTransaction(new String[]{latestPurchase.notificationId}); if(mCompletedHandler != null){ mCompletedHandler.sendEmptyMessage(0); } else { Log.e(TAG, "verifyPurchase error. Handler not instantiated. Have you called setCompletedHandler()?"); } } public static void stopService(){ mContext.stopService(new Intent(mContext, BillingService.class)); mService = null; mContext = null; mCompletedHandler = null; Log.i(TAG, "Stopping Service"); } } 

Thx для вашей помощи в Advance

С наилучшими пожеланиями

сафари

аппендикс


манифест

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.stepforward" android:versionCode="6" android:versionName="1.3.2" > <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/StepForward.Theme" android:debuggable="false" > <activity android:label="@string/app_name" android:name=".SplashActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ChannelActivity" ></activity> <activity android:name=".billing.AppMainTest"></activity> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="com.android.vending.BILLING" /> <!-- In-App-Einkäufe für Donate --> <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> </manifest> 

LogCat (дополнительная информация)

 12-07 13:58:14.334: I/BillingService(20997): Starting 12-07 13:58:14.364: D/dalvikvm(20997): GC_EXTERNAL_ALLOC freed 15K, 58% free 2919K/6791K, external 414K/926K, paused 22ms 12-07 13:58:23.864: E/BillingService(20997): BillingHelper not fully instantiated 12-07 13:58:23.864: I/BillingService(20997): Can't purchase on this device 

Solutions Collecting From Web of "In-App-Billing – BillingHelper полностью не создан"

Если вы посмотрите на этот метод:

  private static boolean amIDead() { if (mService == null || mContext == null) { Log.e(TAG, "BillingHelper not fully instantiated"); return true; } else { return false; } } 

Этот журнал печатается, когда ваша служба имеет нулевой или контекст. Aaaand ваше обслуживание равно null, когда:

  protected static void instantiateHelper(Context context, IMarketBillingService service) { mService = service; mContext = context; } 

InstantiateHelper не называется aaand

  @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "Market Billing Service Connected."); mService = IMarketBillingService.Stub.asInterface(service); BillingHelper.instantiateHelper(getBaseContext(), mService); } 

Вызывается, когда ваша Служба подключена, и я вижу, что вы пытаетесь подключиться к сервису следующим образом:

  startService(new Intent(mContext, BillingService.class)); 

ТАК:

Вы объявили услугу в своем манифесте?

  <application ... <service android:name=".BillingService" /> ... </application> 

РЕДАКТИРОВАТЬ

Я был прав 🙂 Это всего лишь ваш тег службы вне вашего тега приложения.

См. Здесь: https://stackoverflow.com/a/5439157/413127