Andrey
Andrey

Reputation: 1110

handleActivityResult: data is null when implementing inapp billing v3

I'm using this implementation: https://github.com/anjlab/android-inapp-billing-v3

Everything by the list (Android Studio, clean project):

_

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();
    }
}

Manifest just in case:

<?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>

I expect it to offer a purchase to me on start or display some kind of error to the console, instead I'm getting this (if running on device):

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@[email protected]@[email protected]) 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!

Or this (if running on an emulator):

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)

What I've tried and checked so far:

Edit: After some suggestions, I've changed the onCreate to this:

@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");
            }
        }
    });
}

Nothing changed. The log output is like this:

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!

Upvotes: 1

Views: 1587

Answers (2)

Andrey
Andrey

Reputation: 1110

The problem was in the device. You cannot test the billing on an emulator and it seems that the billing is broken on my device, in other apps as well (they are giving out some kind of "Unknown error" every time I try to pay).

Apparently, the permissions for the Google Play app or Google services were revoked, after bringing them back from the phone settings - permissions it works fine.

Upvotes: 1

Nirav Bhavsar
Nirav Bhavsar

Reputation: 2233

Might be possible that onBillingInitialized() is called before the constructor finishes.

Instantiating a BillingProcessor with late initialization

The basic new BillingProcessor(...) actually binds to Play Services inside the constructor. This can, very rarely, lead to a race condition where Play Services are bound and onBillingInitialized() is called before the constructor finishes, and can lead to NPEs. To avoid this, we have the following:

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

and also Before any usage it's good practice to check in-app billing services availability. In some older devices or chinese ones it may happen that Play Market is unavailable or is deprecated and doesn't support in-app billing.

Simply call static method BillingProcessor.isIabServiceAvailable(), if its true then continue.

For more details please refer this link

Upvotes: 0

Related Questions