1

我正在我的 Android 应用程序中实施 InApp 计费。一切正常,但是,我正在尝试将广播接收器与活动分离为清单。尤其是在 Android 的 trivialdrive 示例中的这个建议:

// Important: Dynamically register for broadcast messages about updated purchases.
// We register the receiver here instead of as a <receiver> in the Manifest
// because we always call getPurchases() at startup, so therefore we can ignore
// any broadcasts sent while the app isn't running.
// Note: registering this listener in an Activity is a bad idea, but is done here
// because this is a SAMPLE. Regardless, the receiver must be registered after
// IabHelper is setup, but before first call to getPurchases().

目前有一个扩展类BroadcastReceiver

public class IabBroadcastReceiver extends BroadcastReceiver {
/**
 * The Intent action that this Receiver should filter for.
 */
public static final String ACTION = "com.android.vending.billing.PURCHASES_UPDATED";
private final IabBroadcastListener mListener;

public IabBroadcastReceiver(IabBroadcastListener listener) {
    mListener = listener;
}

@Override
public void onReceive(Context context, Intent intent) {
    if (mListener != null) {
        mListener.receivedBroadcast();
    }
}

/**
 * Listener interface for received broadcast messages.
 */
public interface IabBroadcastListener {
    void receivedBroadcast();
}
}

还有一个实现的类IabBroadcastReceiver.IabBroadcastListener

public class Subscription extends AppCompatActivity implements 
IabBroadcastReceiver.IabBroadcastListener {

IabHelper mHelper;

// Provides purchase notification while this app is running
IabBroadcastReceiver mBroadcastReceiver;

...


// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
        Log.d("IAB", "Query inventory finished.");

        if (mHelper == null) return;

        if (result.isFailure()) {
            Log.d("IAB", "Failed to query inventory: " + result);
            return;
        }

        if (inventory.getSkuDetails(SKU_MONTHLY_TTS) != null
                && inventory.getSkuDetails(SKU_YEARLY_TTS) != null) {
            ...
          }


        Log.d("IAB", "Query inventory was successful.");

        /*
         * Check for items we own. Notice that for each purchase, we check
         * the developer payload to see if it's correct! See
         * verifyDeveloperPayload().
         */

        ...

        Log.d("IAB", "Initial inventory query finished; enabling main UI.");
    }
};
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
    public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
        Log.d("IAB", "Purchase finished: " + result + ", purchase: " + purchase);

        // if we were disposed of in the meantime, quit.
        if (mHelper == null) return;

        if (result.isFailure()) {
            Log.d("IAB", "Error purchasing: " + result);
            return;
        }
        if (!verifyDeveloperPayload(purchase)) {
            Log.d("IAB", "Error purchasing. Authenticity verification failed.");
            return;
        }

        Log.d("IAB", "Purchase successful.");

        ...
    }
};


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_subscription);


    mHelper = new IabHelper(this, compiledKy);

    mHelper.enableDebugLogging(true);

    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
        @Override
        public void onIabSetupFinished(IabResult result) {
            Log.d("Subscription", "InSetUpFinished: " + result);
            if (!result.isSuccess()) {
                Log.d("Subscription", "Problem setting up In-app Billing: " + result);
                return;
            }

            if (mHelper == null) return;

            // Important: Dynamically register for broadcast messages about updated purchases.
            // We register the receiver here instead of as a <receiver> in the Manifest
            // because we always call getPurchases() at startup, so therefore we can ignore
            // any broadcasts sent while the app isn't running.
            // Note: registering this listener in an Activity is a bad idea, but is done here
            // because this is a SAMPLE. Regardless, the receiver must be registered after
            // IabHelper is setup, but before first call to getPurchases().
            mBroadcastReceiver = new IabBroadcastReceiver(Subscription.this);
            IntentFilter broadcastFilter = new IntentFilter(IabBroadcastReceiver.ACTION);
            registerReceiver(mBroadcastReceiver, broadcastFilter);

            // IAB is fully set up. Now, let's get an inventory of stuff we own.
            Log.d("IAB", "Setup successful. Querying inventory.");
            try {
                List<String> additionalSkuList = new ArrayList<String>();
                ...
                mHelper.queryInventoryAsync(true, null, additionalSkuList, mGotInventoryListener);
            } catch (IabHelper.IabAsyncInProgressException e) {
                Log.d("IAB", "Error querying inventory. Another async operation in progress.");
            }
        }
    });

    Button monthlySubButton = (Button) findViewById(R.id.monthlySubButton);
    monthlySubButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (!mHelper.subscriptionsSupported()) {
                Log.d("IAB","Subscriptions not supported on your device yet. Sorry!");
                return;
            }
            try {
                ...
                mHelper.launchPurchaseFlow(Subscription.this, ..., IabHelper.ITEM_TYPE_SUBS,
                        oldSku, 10001, mPurchaseFinishedListener, "");
            } catch (IabHelper.IabAsyncInProgressException e) {
                Log.d("IAB", e.getMessage());
            }
        }
    });

    ...
}

/** Verifies the developer payload of a purchase. */
boolean verifyDeveloperPayload(Purchase p) {
    String payload = p.getDeveloperPayload();

    ...
    return true;
}

@Override
protected void onDestroy() {
    super.onDestroy();

    if (mBroadcastReceiver != null) {
        unregisterReceiver(mBroadcastReceiver);
    }

    Log.d("IAB", "Destroying helper.");
    if (mHelper != null) {
        mHelper.disposeWhenFinished();
        mHelper = null;
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d("IAB", "onActivityResult(" + requestCode + "," + resultCode + "," + data);
    if (mHelper == null) return;

    if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
        super.onActivityResult(requestCode, resultCode, data);
    }
    else {
        Log.d("IAB", "onActivityResult handled by IABUtil.");
    }
}

@Override
public void receivedBroadcast() {
    // Received a broadcast notification that the inventory of items has changed
    Log.d("IAB", "Received broadcast notification. Querying inventory.");
    try {
        mHelper.queryInventoryAsync(mGotInventoryListener);
    } catch (IabHelper.IabAsyncInProgressException e) {
        Log.d("IAB", "Error querying inventory. Another async operation in progress.");
    }
}
}

我正在尝试在清单中添加一个接收器,但它给了我一个错误:

</application>
...
<activity
        android:name=".controller.Subscription"
        android:label="Subscription"
        android:parentActivityName=".controller.MainActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".controller.MainActivity" />
    </activity>

    <receiver android:name=".controller.Subscription"  android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
        </intent-filter>
    </receiver>
</application>

Error Message:.controller.Subscription is not assignable to 'android.content.BroadcastReceiver'

该类Subscription位于正确的目录中(在控制器包下)。我的Subscription班级是否必须扩展 IabBroadcastReceiver 班级而不是实施IabBroadcastReceiver.IabBroadcastListener?我仍然想扩展AppCompactActivity,想知道是否有任何方法可以解决这个问题。似乎没有在线示例显示如何使用清单中注册的广播接收器实现 inApp 计费 api。提前谢谢你的帮助!

4

2 回答 2

1

controller.Subscription 不可分配给“android.content.BroadcastReceiver”

这意味着,这Subscription不是 a 的后代BroadcastReceiver。您已Subscription在清单中注册为receiver,但实际上它不是 的子类BroadcastReceiver

我的Subscription班级是否必须扩展IabBroadcastReceiver班级而不是实施IabBroadcastReceiver.IabBroadcastListener

为了receiver在清单中注册一个类,它应该是 的后代(直接或间接)BroadcastReceiver。因此,Subscription应该extends BroadcastReceiverextends IabBroadcastReceiver

我仍然想扩展AppCompactActivity

您不能使一个类既是活动又是接收者(Java 不支持多重继承)。

您仍然可以IabBroadcastReceiver通过清单注册为<receiver>. 但我想知道这背后的原因是什么?显然,当您的应用程序处于非活动状态时,您永远不会收到任何广播,因为您应该在应用程序中启动购买流程,这就是BroadcastReceiver动态注册和取消注册更有意义的原因。请注意,通过清单注册接收器会使您收到来自其他应用程序的购买广播,您很可能对此不感兴趣。

请参阅文档

不要在应用清单中注册此广播接收器。如果用户在应用程序未运行时进行购买,则在清单中声明接收者可能会导致系统启动应用程序来处理意图。此行为不是必需的,并且可能会令用户烦恼。要了解用户在应用程序未运行时进行的任何购买,请在用户启动应用程序时调用getPurchases() 。

于 2017-08-20T15:40:59.593 回答
0

这通常是因为您在 \controller\ 包下没有Subscription类。您的代码中的一切看起来都很好(假设您在清单中添加了相应的意图过滤器)。因此,请确保您的Subscription类位于正确的包(或文件夹)中。

于 2017-08-15T03:58:12.790 回答