handleActivityResult:实施inapp billing v3时数据为空

handleActivityResult: data is null when implementing inapp billing v3

我正在使用这个实现:https://github.com/anjlab/android-inapp-billing-v3

列表中的所有内容(Android Studio,干净的项目):

_

package com.example.myappnamehere;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.anjlab.android.iab.v3.BillingProcessor;
import com.anjlab.android.iab.v3.TransactionDetails;

public class MainActivity extends Activity implements BillingProcessor.IBillingHandler {

    BillingProcessor bp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i("MainActivity", "on Create");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bp = new BillingProcessor(this, "[my license key here]", this);
    }

    @Override
    public void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails details) {
        Log.i("MainActivity", "Product purchased");
    }

    @Override
    public void onPurchaseHistoryRestored() {
        Log.i("MainActivity", "Purchase History Restored");

    }

    @Override
    public void onBillingError(int errorCode, @Nullable Throwable error) {
        Log.e("MainActivity", error.getMessage());

    }

    @Override
    public void onBillingInitialized() {
        Log.i("MainActivity", "Billing initialized");
        bp.purchase(MainActivity.this, "[my inapp product id here]");
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i("MainActivity", "Activity Result");
        if (!bp.handleActivityResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
    @Override
    public void onDestroy() {
        Log.i("MainActivity", "Destroy");
        if (bp != null) {
            Log.i("MainActivity", "bp release");
            bp.release();
        }
        super.onDestroy();
    }
}

清单以防万一:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myappnamehere">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="com.android.vending.BILLING" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

我希望它能在启动时向我提供购买或向控制台显示某种错误,而我却得到这个(如果 运行 在设备上):

W/art: Failed execv(/system/bin/dex2oat --runtime-arg -classpath --runtime-arg  --instruction-set=arm64 --instruction-set-features=smp,a53 --runtime-arg -Xrelocate --boot-image=/system/framework/boot.art --non-interactive --runtime-arg -Xms64m --runtime-arg -Xmx512m --instruction-set-variant=generic --instruction-set-features=default --dex-file=/data/app/pro.yakninja.usermobi-1/split_lib_slice_9_apk.apk --oat-file=/data/dalvik-cache/arm64/data@app@com.example.myappnamehere-1@split_lib_slice_9_apk.apk@classes.dex) because non-0 exit status
...
W/System: ClassLoader referenced unknown path: /data/app/com.example.myappnamehere-1/lib/arm64
I/InstantRun: starting instant run server: is main process
I/MainActivity: on Create
D/AccessibilityManager: current package=com.example.myappnamehere, accessibility manager mIsFinalEnabled=false, mOptimizeEnabled=false, mIsUiAutomationEnabled=false, mIsInterestedPackage=false
W/System: ClassLoader referenced unknown path: /system/app/MiuiContentCatcher/lib/arm64
D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
I/MainActivity: Billing initialized
I/Adreno: ...
I/OpenGLRenderer: Initialized EGL, version 1.4
I/MainActivity: Activity Result
E/iabv3: handleActivityResult: data is null!

或者这个(如果 运行 在模拟器上):

I/InstantRun: starting instant run server: is main process
I/MainActivity: on Create
D/OpenGLRenderer: HWUI GL Pipeline
D/: HostConnection::get() New Host Connection established 0x9b3e4380, tid 9990
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
D/OpenGLRenderer: Swap behavior 0
D/EGL_emulation: eglCreateContext: 0x9b685120: maj 3 min 0 rcv 3
D/EGL_emulation: eglMakeCurrent: 0x9b685120: ver 3 0 (tinfo 0x9b683290)
D/EGL_emulation: eglMakeCurrent: 0x9b685120: ver 3 0 (tinfo 0x9b683290)

到目前为止我已经尝试和检查的内容:

编辑:根据一些建议,我将 onCreate 更改为:

@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.i("MainActivity", "on Create");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    bp = BillingProcessor.newBillingProcessor(this, "[license key]", this); // doesn't bind
    bp.initialize(); // binds

    payButton = (Button)findViewById(R.id.payButton);
    payButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.i("MainActivity", "button clicked");

            boolean isAvailable = BillingProcessor.isIabServiceAvailable(v.getContext());
            if(isAvailable) {
                Log.i("MainActivity", "isIabServiceAvailable");
            }
            else {
                Log.e("MainActivity", "isIabService is not Available");

            }

            boolean isOneTimePurchaseSupported = bp.isOneTimePurchaseSupported();
            if(isOneTimePurchaseSupported) {
                Log.i("MainActivity", "OneTimePurchase is supported");
                bp.purchase(MainActivity.this, "android.test.purchased");
            }
            else {
                Log.e("MainActivity", "OneTimePurchase is not supported");
            }
        }
    });
}

没有任何变化。日志输出是这样的:

I/MainActivity: on Create
I/MainActivity: Billing initialized
I/MainActivity: button clicked
I/MainActivity: isIabServiceAvailable
I/MainActivity: OneTimePurchase is supported
I/MainActivity: Activity Result
E/iabv3: handleActivityResult: data is null!

可能 onBillingInitialized() 在构造函数完成之前被调用。

实例化延迟初始化的 BillingProcessor

基本 new BillingProcessor(...) 实际上绑定到 constructor 内的 Play 服务。这很少会导致竞争条件,即 Play 服务被绑定并且 onBillingInitialized() 在构造函数完成之前被调用,并且可能导致 NPE。为了避免这种情况,我们有以下内容:

bp = BillingProcessor.newBillingProcessor(this, "YOUR LICENSE KEY FROM GOOGLE PLAY CONSOLE HERE", this); // doesn't bind
bp.initialize(); // binds

并且在使用之前,最好检查应用内结算服务的可用性。在某些较旧的设备或中文设备中,可能会出现 Play Market 不可用或已弃用且不支持应用内结算的情况。

只需调用静态方法BillingProcessor.isIabServiceAvailable(),如果为真则继续。

更多详情请参考此link

问题出在设备上。您无法在模拟器上测试计费,似乎计费在我的设备上出现问题,在其他应用程序中也是如此(每次我尝试付款时他们都会给出某种 "Unknown error")。

显然,Google Play 应用程序或 Google 服务的权限在从 phone 设置中恢复后被撤销 - 权限正常。