Adyen / adyen-ios

Adyen iOS Drop-in and Components
https://docs.adyen.com/checkout/ios
MIT License
151 stars 120 forks source link

[ISSUE] - Safari can not open as the address is invalid #167

Closed basheer411 closed 3 years ago

basheer411 commented 4 years ago

Description: I am trying to Implement iDeal Component Integration. can load action object with RedirectComponent. encountered an issue with return Url

Issue : The next steps encountered an issue as "Safari can not open as the address is invalid" (PFA) - which I suspect its URI schema issue. As we are not supporting URI Schema's in my app, any alternative ways other than URI Schema?

Screenshot 2020-05-22 at 12 36 49 AM
joostvandijk commented 4 years ago

Hi @basheer411,

What is the returnUrl you are currently passing in your request to /payments?

Best,

Joost

basheer411 commented 4 years ago

Hi @joostvandijk , I am sending The returnUrl as "myapp://APPBUNDLEIDENTIFIER" and the payload will be {"issuer":"1121","returnURL":"myapp:\/\/com.org.sport","type":"IDEAL"}

Basheer

joostvandijk commented 4 years ago

I see, and is there any reason why you can not register a URI scheme as described here?

basheer411 commented 4 years ago

Yes, there is a reason can we have any alternates to get them worked without URI?

joostvandijk commented 4 years ago

Hi Bas, there is no other way to reliably intercept a redirect from Safari View Controller.

descorp commented 4 years ago

hi @basheer411

There is no technical limitation on using Universal links from the SDK side. The main concern with universal links is that if the user clicks the top right corner to return in safari, the next time the app won't be opened. Universal links is a perfect tool for features paired on mobile and web, but - as @joostvandijk mentioned above - it is not a reliably redirect technique.

I am going to close this ticket for now. If you have any questions or ideas, feel free to continue in this thread.

basheer411 commented 4 years ago

Hi @descorp

when I am sending a universal link (retrurnUrl ) from /payments. it's not opening the app. The same URL when I am accessing from outside of the app it's working as expected.

is there any limitation from Adyen side?

In general, Pasting a Universal Link directly into the Safari URL field doesn’t cause the app to open automatically. If you do this, you will have to manually pull the website down so that a prompt will appear at the top asking you to open the respective app.

But, if you paste links in Notes(app), Mail(app) or even if you go to Facebook on Safari and then click on a universal link, the app opens directly.

I think the Adyen redirect component is doing the same as above, as its on the SafariViewController, unable to open the app.

Thanks, Basheer.

descorp commented 4 years ago

Hi @basheer411

How do you call a RedirectComponent? To trigger Universal App URL redirect you need to call redirectComponentInstance.handle(_ action: RedirectAction).

There is a static method RedirectComponent.applicationDidOpen(from: url) - it is not suitable for Universal App URLs

basheer411 commented 4 years ago

Hi @descorp ,

Here is my code :

private func presentRedirectComponent(with action: RedirectAction) {
        let component = RedirectComponent(style: redirectComponentStyle)
        component.delegate = self
        component.presentingViewController = UIApplication.topViewController()
        redirectComponent = component
        component.handle(action)
    }

The app is triggering outside. when I am trying to open the app from Safari the App state remains the same on RedirectComponent webpage.

RedirectComponent delegates also not triggered func didSubmit(_ data: ActionComponentData, from component: ActionComponent) func didFail(with error: Error, from component: ActionComponent)

I am not using RedirectComponent.applicationDidOpen(from: url) to open universal links

basheer411 commented 4 years ago

Hi @descorp ,

will you please explain when RedirectComponent invokes/calls/hits the didProvide method from the ActionComponentDelegate. to get the contents of data.details to pass this to your server.

I can see didFail is hitting on cancel action of the attached screenshot.

on continue action I am switching to the browser and redirecting back to the app. I assume it will call didProvide still, it's not hitting didProvide.

I have gone through these steps: https://docs.adyen.com/checkout/ios/components#step-4-additional-client-app , It's not clear so far. May I know what exactly needs to do after redirecting back to the app.

IMG_10AB0B3EBE40-1

descorp commented 4 years ago

Hi @basheer411

Here is the process described in docs:

  1. Make a /payment request. Make sure that "returnURL" is your custom URL scheme or Universal App Link URL;
  2. Checkout API generates RedirectAction to 3rd-party app / website, RedirectComponent opens it;
  3. Shopper finishes 3rd party payment flow on web/app; 3rd party call "returnURL" with payment details as query;
  4. Handles Custom URL Scheme or Universal App Link in our AppDelegate and call RedirectComponent.applicationDidOpen(from: url);
  5. SDK will gather all info from url's query and return delegate.didProvide(...).
basheer411 commented 4 years ago

Hi @descorp ,

I think the issue is at point number 5 on the above comment. you are right, that SDK is appending all info (payload, status, type) to the URL(Univeral Link), but it's not firing delegate.didProvide(...)

I think its because of the session expired after redirect from the app

is there any issue If I will manage the URL by extracting with URL components fetch ActionComponentData (payload, status, type etc..) in my custom class/method instead of waiting for delegate.didProvide(...) to fire and proceed for/details call?

In both ways, the result will remain the same.

descorp commented 4 years ago

Do you persist RedirectComponent up until the payment is confirmed?

is there any issue

No, not specifically. The network call have to be managed on app level any way. If you need an example - this is how AdditionalDetails is gathered from url

But I would recommend to figure out what is happening with delegate.didProvide(...) first..

basheer411 commented 4 years ago

Thanks for confirming no issues with doing manually.

But I would recommend to figure out what is happening with delegate.didProvide(...) first..

I think the while app switching, RedirectComponent session has existed. but when redirecting back to the app RedirectComponent doesn't exist. The appDelegate hits restorationHandler and we handling the link (navigate to ideal payment VC which was initiated earlier) by this time RedirectComponent will not exist so that the delegates will not respond and leading /details to call manually. `

descorp commented 4 years ago

Hi @basheer411

There is no session in RedirectComponent. The idea to persist RedirectComponent is to store a reference to ActionComponentDelegate - the one that will return didProvide(...) when Universal Link processed. In other words, to get delegate.didProvide(...) firing you have to keep the RedirectComponent instance.

basheer411 commented 4 years ago

Thanks, will do that.

re the Previous comment, AdditionalDetails is gathered from URL we are receiving the TYPE keyword too, and we getting the value as type=complete will it remains same at every instance? (even with failures/errors during the payments.. )

descorp commented 4 years ago

Hi @basheer411

Could you share a url, you receive by Universal App Link?

The URL supposed to contain one or several query parameters from CodingKeys and encrypted blobs as values.

I am not aware of any 'TYPE' keyword especially with 'type=complete'.

(even with failures/errors during the payments.. )

Status of the payment will be confirmed by Adyen API and returned back to the app as result of /payments/details call. The only reliable source of truth is a resultCode

basheer411 commented 4 years ago

URL looks like this The suffix will be my Universal Link

we are getting resultCode also here.

descorp commented 4 years ago

Hi @basheer411

Yes, the link looks good to me. The query parameters are added by the payment method. The resultCode is reliable here, but I would advise always checking the Adyen API response: some other redirect-based payment methods might not have this query parameter.

descorp commented 4 years ago

Hi @basheer411

Were you able to successfully perform a Universal Link redirect?

basheer411 commented 4 years ago

Hi @descorp , I have tested in UAT, they are working as expected, we are not relay on delegate.didProvide(...) we just capturing paymentData from the universal link and sending to /details.

The purpose of Universal link to redirect back to the app when user paying through Banking App. I have a question around, .i.e. what is the behaviour of completing the payment without banking app? will it call Universal link? as we are sending this to the /payments

descorp commented 4 years ago

Hi @basheer411

Glad that you were able to make Universal link work, well done!

completing the payment without banking app?

You mean via the Bank's web site when shoppers have no app installed?

All redirect-based payments (Paypal, iDEAL, WeChat, CardComponent with web 3DS e.t.c) are expected to call a "returnURL" after completion. There is no difference whether it was done by SFSafariViewController or 3rd party app.

descorp commented 3 years ago

Hi @basheer411

I am going to close this ticket for now, since we confirmed Universal Links to work as expected. If you have any questions or ideas, feel free to continue in this thread.

fidoafif commented 3 years ago

Hi @descorp ,

I think the issue is at point number 5 on the above comment. you are right, that SDK is appending all info (payload, status, type) to the URL(Univeral Link), but it's not firing delegate.didProvide(...)

I think its because of the session expired after redirect from the app

is there any issue If I will manage the URL by extracting with URL components fetch ActionComponentData (payload, status, type etc..) in my custom class/method instead of waiting for delegate.didProvide(...) to fire and proceed for/details call?

In both ways, the result will remain the same.

Hi it seem delegate.didProvide(...) not firing after authorized payment and get type = complete,

fidoafif commented 3 years ago

https://user-images.githubusercontent.com/9498128/115643765-ff8b5f80-a34f-11eb-9eaf-170604e79372.mov

My case is stuck on inApp safari browser, the return url that I used is deep link my-app://, and the deep link is working on safari app

descorp commented 3 years ago

Hi @fidoafif

Thanks for reaching out!

return url that I used is deep link my-app://, and the deep link is working on safari app

You mean if you call my-app:// URL on Safari - system asks if you want to open your app?

Just to clarify: You have flowed all steps on how to handle the redirect result:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
        RedirectComponent.applicationDidOpen(from: url)
        return true
    }

From what I see on the video above - either the redirect didn't happen at all (something is wrong with returnURL) or it was not handled(the RedirectComponent.applicationDidOpen(from: url) not called). Redirect supposed to happen when you see "Your payment is authorised" page, no need to press "Continue" button (to try it our - set "returnUrl" : "http://www.google.com").

When RedirectComponent.applicationDidOpen(from: url) is called - it will trigger func didProvide(_ data: ActionComponentData, from component: DropInComponent) on DropInComponentDelegate