Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FlutterInappPurchase.connectionUpdated not working #272

Closed
ThangNguyen91 opened this issue Mar 11, 2021 · 11 comments
Closed

FlutterInappPurchase.connectionUpdated not working #272

ThangNguyen91 opened this issue Mar 11, 2021 · 11 comments

Comments

@ThangNguyen91
Copy link

ThangNguyen91 commented Mar 11, 2021

Version of flutter_inapp_purchase

flutter_inapp_purchase: ^3.0.1

Platforms you faced the error (IOS or Android or both?)

both Android and IOS

Expected behavior

FlutterInappPurchase.connectionUpdated working

Actual behavior

FlutterInappPurchase.connectionUpdated not working when call await FlutterInappPurchase.instance.initConnection

Tested environment (Emulator? Real Device?)

Iphone 7plus (Real Device), Samsung j7 (Real Device)

Steps to reproduce the behavior

Step 1:
var result = await FlutterInappPurchase.instance.initConnection;
Step 2:
_conectionSubscription =
FlutterInappPurchase.connectionUpdated.listen((connected) {
_connectedResult = connected;
print('FlutterInappPurchase connected $connected');
});

@github-actions
Copy link

This issue is stale because it has been open 90 days with no activity. Leave a comment or this will be closed in 7 days.

@deakjahn
Copy link
Contributor

deakjahn commented Nov 14, 2021

I have something even more sinister right now. The initConnection handler calls back

channel.invokeMethod("connection-updated", item.toString());

And it seems that this not only doesn't arrive to the Dart side but it basically hangs the process and it never actually goes on to the next line. This means that await FlutterInappPurchase.instance.initConnection never returns.

@hyochan
Copy link
Owner

hyochan commented Nov 15, 2021

line

Oh may I know which version you are using?

@deakjahn
Copy link
Contributor

deakjahn commented Nov 15, 2021

Always the last one, 5.1.0.

Now I made a local copy and I keep investigating but practically, the whole channel communication seems to have problems. Strange.

Basically, I get into the initConnection branch in the Java file, onBillingSetupFinished() is called, the responseCode is checked but setting the result never returns back to the Dart side. I've been using platform channels myself for ages, I've never seen such an error yet... :-)

@deakjahn
Copy link
Contributor

deakjahn commented Nov 15, 2021

This is my local code now:

Future<String?> initConnection() async {
  if (_platform.isAndroid) {
    await _setPurchaseListener();
    print("before call");
    final String? result = await _channel.invokeMethod('initConnection');
    print("never reaches here");
    return result;
  } else ...
}

@hyochan
Copy link
Owner

hyochan commented Nov 15, 2021

@deakjahn If I remember correctly, there were lots of question asked for module not being updated. Could you kindly remove the cache and ensure that you have the fresh FlutterInappPurchase module?

@deakjahn
Copy link
Contributor

I have no cache issues for sure. Right know I'm working on a local copy of the module and all print() and Log.d() printouts I put into the source are immedately picked up on the next compile, so there's no way for anything stale to sneak in. :-)

@deakjahn
Copy link
Contributor

deakjahn commented Nov 15, 2021

On an unrelated note, because I checked out the plugin registration as well, I'd suggest to include the same checks into registerWith as well:

public static void registerWith(Registrar registrar) {
  isAndroid = isPackageInstalled(registrar.context(), "com.android.vending");
  isAmazon = isPackageInstalled(registrar.context(), "com.amazon.venezia");

  // In the case of an amazon device which has been side loaded with the Google Play store,
  // we should use the store the app was installed from.
  if (isAmazon && isAndroid) {
    if (isAppInstalledFrom(registrar.context(), "amazon")) {
      isAndroid = false;
    } else {
      isAmazon = false;
    }
  }

or even better, put the check into a separate function and just call from both places.

@deakjahn
Copy link
Contributor

deakjahn commented Nov 15, 2021

Well, nothing to do with my trouble, but here it is if you're interested, I did it during my attempts. :-)

The common function:

private void onAttached(Context context, BinaryMessenger messenger) {
  isAndroid = isPackageInstalled(context, "com.android.vending");
  isAmazon = isPackageInstalled(context, "com.amazon.venezia");

  // In the case of an amazon device which has been side loaded with the Google Play store,
  // we should use the store the app was installed from.
  if (isAmazon && isAndroid) {
    if (isAppInstalledFrom(context, "amazon")) {
      isAndroid = false;
    } else {
      isAmazon = false;
    }
  }

  if (isAndroid) {
    androidInappPurchasePlugin = new AndroidInappPurchasePlugin();
    androidInappPurchasePlugin.setContext(context);
    setupMethodChannel(messenger, androidInappPurchasePlugin);
  } else if (isAmazon) {
    amazonInappPurchasePlugin = new AmazonInappPurchasePlugin();
    amazonInappPurchasePlugin.setContext(context);
    setupMethodChannel(messenger, amazonInappPurchasePlugin);
  }
}

and both just call this:

@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
  onAttached(binding.getApplicationContext(), binding.getBinaryMessenger());
}

public static void registerWith(Registrar registrar) {
  FlutterInappPurchasePlugin instance = new FlutterInappPurchasePlugin();
  instance.onAttached(registrar.context(), registrar.messenger());
}

@deakjahn
Copy link
Contributor

deakjahn commented Nov 15, 2021

@hyochan OK. I found it, finally. You won't like it that much but you'll have to change it. :-) First I'll describe it, then I'll try to look whether I can provide you with a PR. My current code is rather different from your current one, I tweaked it quite a lot but I'll try to incorporate what's needed in your original code.

The underlying problem is relatively new:

Plugins now have to handle threading and make sure that they report the result on the UI thread even if their actual platform code runs on a different one. One good solution is the MethodResultWrapper that the geocoder plugin also applies, this uses a Runnable to run the callbacks (both you calling back to the Dart side and reporting success or failure in result) on the UI thread.

@deakjahn
Copy link
Contributor

And I made my first test purchase again, successfully. So, let's see the PR. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants