ionic-team / capacitor

Build cross-platform Native Progressive Web Apps for iOS, Android, and the Web ⚡️
https://capacitorjs.com
MIT License
11.19k stars 951 forks source link

[Bug]: Cordova plugin intercepts Capacitor plugins calls #7361

Open masimplo opened 1 month ago

masimplo commented 1 month ago

Capacitor Version

💊 Capacitor Doctor 💊

Latest Dependencies:

@capacitor/cli: 5.7.3 @capacitor/core: 5.7.3 @capacitor/android: 5.7.3 @capacitor/ios: 5.7.3

Installed Dependencies:

@capacitor/cli: 5.7.3 @capacitor/android: 5.7.3 @capacitor/ios: 5.7.3 @capacitor/core: 5.7.3

[success] iOS looking great! 👌 [success] Android looking great! 👌

Other API Details

npm --version    
10.2.3

node --version                                         
v18.19.0

pod --version            
1.15.2

Platforms Affected

Current Behavior

I am using cordova-plugin-purchase version 3.10.1 (latest) and when I ask for the native payment sheet to open in order to make a purchase, any capacitor plugin that needs to use startActivityResult to send something back over the bridge, gets intercepted by onActivityResult of the Cordova plugin, even though the payment sheet has been dismissed due to the fact that activityResultCallback inside bridge.java remains set and Cordova plugin results (as well as capacitor plugin results using the now deprecated request codes) take precedence over newer capacitor plugin callbacks inside bridgeActivity.java.

This happens due to this code inside the bridgeActivity.java class

        if (!bridge.onActivityResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        }

that gives precedence to Cordova plugins if the Capacitor plugin is not using the deprecated RequestCode as shown here:

boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        PluginHandle plugin = getPluginWithRequestCode(requestCode);

        if (plugin == null || plugin.getInstance() == null) {
            Logger.debug("Unable to find a Capacitor plugin to handle requestCode, trying Cordova plugins " + requestCode);
            return cordovaInterface.onActivityResult(requestCode, resultCode, data);
        }

and

public boolean onActivityResult(int requestCode, int resultCode, Intent intent) {
        CordovaPlugin callback = activityResultCallback;
        ....
        if (callback != null) {
            LOG.d(TAG, "Sending activity result to plugin");
            initCallbackService = null;
            savedResult = null;
            callback.onActivityResult(requestCode, resultCode, intent);
            return true;
        }

as activityResultCallback is still set from the Cordova payment plugin.

Practically what this means is that whenever the payment sheet appears, any capacitor plugin using startActivityResult (for instance SharePlugin) does not have a way to return information back to the JS code for it first call after the payment sheet is shown. Following calls to the SharePlugin will work.

I understand this might be an issue introduced by the plugin (and I have opened an issue on the plugin's repo also) but I believe Capacitor should be able to prevent this behaviour as this could also have security implications in a misconfigured project, which is the reason I opened this issue here as well.

Expected Behavior

Both Cordova and Capacitor plugins should work together without interference

Project Reproduction

Since creating a sample project setting the purchase plugin up requires setting up google play and products, I instead created a short video demonstrating the issue with along with the debugging flow. https://www.youtube.com/watch?v=SRxTy1jfD84

Additional Information

No response

masimplo commented 1 month ago

For reference, here is the issue I opened on the plugin side also https://github.com/j3k0/cordova-plugin-purchase/issues/1549