In my iOS application, I need to accept payments from the user. I am using UPI for the same. I have followed the following document provided by UPI
http://www.npci.org.in/documents/UPI-Linking-Specs-ver-1.1_draft.pdf
I have created a deeplink as stated in the document. UIApplication.shared.open is used to open the deeplink url so that it opens any installed PSP(Payment Service Provider) application in my phone(like PhonePe, BHIM etc)
func payButtonClicked() {
guard let urlString = "upi://pay?pa=samplevpa#ybl&pn=Sample Name&am=1&cu=INR".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
else {
return
}
guard let url = URL(string: urlString) else {
return
}
if !UIApplication.shared.canOpenURL(url) {
print("url cannot be opened")
return
}
UIApplication.shared.open(url, options: [:], completionHandler: { (success) in
print(success)
})
}
I have registered my application with custom URL schemes and have added the scheme upi for ApplicationQueriesScheme in plist file
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>SampleApp</string>
</array>
<key>CFBundleURLName</key>
<string>com.company.SampleApp</string>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>upi</string>
</array>
It is opening the PSP application and I'm able to make the transaction. The problem is I'm not able to get the response back from the PSP application. There is no callback method to UIApplication.shared.open method. I need to get the status of the transaction back from the PSP application and show the status to the user. Any help appreciated
the NPCI UPI Linking Specification states that the URL parameter used in the payment link is for information purpose which the payment apps may use to provide additional information to the payer upon clicking the link.
The link is only expected to show transaction details by the merchant or party that invoked the transaction.
It is not meant as a callback URL or a web hook for completion of transaction.
Based on the below workflow, you need to have a tie up with Payer/Payee PSP to get notified for your payments. In your scenario, you are required to check with your bank PSP for getting notified on the payment receipt to your accoutns.
I could not see a way for individual Initiator to get notified.
Feel free to correct me.
Have not tried it but it was mentioned in the document about a url parameter on clicking of which we should show the transaction details to the user.
This should be a URL when clicked provides customer with further
transaction details like complete bill details, bill copy, order
copy, ticket details, etc. This can also be used to deliver digital
goods such as mp3 files etc. after payment.
We could send a url with a url scheme that redirects to the app or an universal link that our app can handle.
Again I have not tried this so I do not know if this works as I think it should or whether it would exactly solve your issue.
https://www.npci.org.in/sites/all/themes/npcl/images/PDF/UPI_Linking_Specs_ver_1.5.1.pdf
You can use the url parameter to pass your website url with the get method with order id or payment id as parameter. Once the payment is successful, it is mandate the UPI provider to hit the URL.
The purpose of the URL should be keep updating the transaction status and trigger then end user an email or SMS with the transaction status.
Related
The Problem:
I am building an app that uses PayPal for payments, and I set up universal links so that the user gets redirected into the app after the user has confirmed the payment at PayPal's site.
Universal links are working in general. But here is what I have discovered:
The following scenario works:
App opens the nextActionUrl from PayPal using SFSafariViewController.
User has to log in and presses the login button.
User presses the confirmation button on the PayPal site.
PayPal redirects to the return_url that was provided when creating the payment intent.
The browser closes, and the user gets redirected into the app.
Now when the user has just recently logged into PayPal then PayPal does not show the login page, instead the user has to only press one button. This scenario fails:
App opens the nextActionUrl from PayPal using SFSafariViewController.
User does not have to log in and presses the confirmation button on PayPal site.
PayPal redirects to the return_url that was provided when creating the payment intent.
The browser opens the website behind the universal link instead of redirecting to the app.
This scenario also works:
App opens the nextActionUrl from PayPal using SFSafariViewController.
User does not have to log in, but actively logs out.
User has to log in and presses the login button.
User presses the confirmation button on the PayPal site.
PayPal redirects to the return_url that was provided when creating the payment intent.
The browser closes, and the user gets redirected into the app.
This happens consistently and reproducible.
Some additional details:
I am developing the App using Flutter
I set up the Runner.entitlements as follows:
...
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:sub.example.com</string>
</array>
...
I set up the Info.plist as follows for deep links with different schema:
...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>sub.example.com</string>
<key>CFBundleURLSchemes</key>
<array>
<string>web+example</string>
</array>
</dict>
</array>
...
I set up the apple-app-site-association file on the website at https://sub.example.com/.well-known/apple-app-site-association as follows:
{
"activitycontinuation": {},
"webcredentials": {},
"applinks": {
"apps": [],
"details": [
{
"appID": "XXXXXXXXXX.com.example.example",
"paths": [ "/*" ]
}
]
}
}
To open the urls from Flutter I am using the package url_launcher and simply call await launchUrl(nextActionUrl)
What I've tried and what I've learned:
I tried many things, before I discovered this consistent behavior. For example:
I connected my device to the mac and opened the console for it in xcode to see how the logs look like when it works and how it looks like when it does not work. I found out that when it works there is a log entry that requests the switch to my App from the SpringBoard-process: [Received trusted open application request for <applicationId> from <FBProcess: ...], but in the cases where it does not work there isn't a rejected request or anything. The SafariViewController does not even seem to try to go the universal link route and instead opens the link as a website directly.
For even more logs, I pressed and hold the volume buttons and clicked the lock screen button until a haptic feedback occurred. After that, I extracted the syslogs that were generated from the settings/privacy section via AirDrop on to the mac. I took a look at the swcutil_show.txt file and the universal link is definitely set up correctly there. I also skimmed around in the other logs, but I couldn't find anything helpful.
I have inspected the url_launcher package to see how it works for iOS and if there may be something wrong, but I didn't really find a problem. I only discovered that the package is using the SFSafariViewController and after some googling I've read the WKWebView would be more suitable, but it didn't seem to be the problem.
I googled a lot and found many problems related with setting up universal links correctly, but no topics about universal links sometimes working and sometimes not. The only thing close I found was that a universal link won't redirect you to your app if you type it into safari directly but if you click it for example from an email.
The workaround that works...
After I confirmed that it consistently works after logging in first, my theory was that it needs at least one navigation between opening the PayPal site in the browser and PayPal redirecting to the universal link.
To confirm my theory I created an intermediate page that redirects the user immediately after the load event to the PayPal site and I was disappointed. It didn't change anything.
Then I thought: Maybe it's the User-Interaction that is needed, and I change the intermediate page to only redirect if the user presses a button. And from there on, redirecting to the App using a universal link always worked.
But this isn't a nice solution - at max, this is an ugly workaround that may help someone.
My question(s)
Now I am not sure if this is a bug on Apple's side since I didn't find anything on the web or maybe even something strange on PayPal's side?
Am I doing something wrong?
Did someone experience the same thing and has a solution?
Thank you for your time and hopefully for your input on this!
I have a WKWebView, the webview will load a link like https://qr.payme.hsbc.com/2/XXXXYYYZZZ.
And there two possible results when the link is loaded,
case 1 is an app called Payme will be opened when user has installed Payme app;
case 2 is webview will be redirected to a static page https://payme.hsbc.com/ when user has not installed Payme app.
My question is how can I know if the Payme app is opened?
You could use deep linking or the apple recommended universal linking to check if an app is installed in a device. With deep linking what you need to do is to acquire a schema of the app that the app has already added. And you could check if the schema can be opened just like you would do for any other type of URLs. Here is an example:
let appSchemeString = "com.myAppScheme://"
let url = URL(string: appSchemeString)!
if UIApplication.shared.canOpenURL(url) {
print("App is present")
} else {
print("App is not")
}
You need to update your info.plist file to include the schemes you'll be opening in the application. You should append this:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>com.myAppScheme</string>
</array>
Here is an entire youtube video link regarding this.
Also, checkout universal-linking.
i defined a deep-link in info.plist like this :
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.myapp.customer</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp.com</string>
</array>
</dict>
</array>
but in Safari there's no reaction to this link and this message shows up :
Safari cannot open the page because the server can not be found
Everything is checked and i did as tutorials and still nothing happens!
The CFBundleURLSchemes field should be filled with a scheme, not a url. Schemes come before the url to tell the browser what action to take. For example, https:// is a scheme that tells the browser to establish a secure connection. An Apple URI scheme is simply you telling the browser that you want URLs with your custom scheme (i.e. customScheme://) to be handled by your app. HTTP and HTTPS are reserved for Safari on iOS. To allow customScheme://example/path to open your app. Just change that field to customScheme.
If you would like to register normal web URLs to handle your links you will have to integrate Universal Links. These can be a pain to set up so I recommend using the Branch iOS SDK. Their deep linking is free and provides more features on top of Universal Links.
Make sure you have this method in AppDelegate.Swift
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if url.scheme != nil && url.scheme!.hasPrefix(""){
//Deep linking link should be like this : 'yourAppScheme'
if(url.host?.contains("page"))!{
if(url.path.contains("/yourhoststring")){
// do some work
}
}
}
//default
return false
}
Your Url scheme should be like this : [scheme]://[host]/[path]
Here is the link for detailed tutorial:
http://blog.originate.com/blog/2014/04/22/deeplinking-in-ios/
I have an application in IOS in which there is a Facebook Login Button.
when ever user clicks this Facebook login button My app redirects the user to the Facebook App installed in my device. So I want to logout the user from the application as soon as he leaves the facebook app and comes to my app.
i redirect the user to the facebook app using
NSUrl url = NSUrl.FromString("fb://profile/<id>");
UIApplication.SharedApplication.OpenUrl(url);
I found the Facebook login documentation. As the documentation described, I think you have added the CFBundleURLTypes, like this:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb[APP_ID]</string>
</array>
</dict>
</array>
It means that Facebook will trigger the openURL to return back to your app via the URLScheme you have set here.
So, you can override OpenUrl(UIApplication app, NSUrl url, NSDictionary options) in AppDelegate.cs, and the parameters url or options contain the information related to Facebook. So, you can identify the resource.
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
Console.WriteLine(url);
Console.WriteLine(options);
return true;
}
According to this, you can do the action you want when return back from Facebook.
Are you using the Xamarin Facebook SDK? If yes you can do this to log out:
new LoginManager().LogOut();
This is a fairly straightforward one: to date, can an iOS app deep link or in any way launch Amazon Music to play a specific song/load an artist or album? How much of this can be done?
If you're feeling really generous, could you describe how to find the URLs to deep link to third party apps like AM, Facebook, Twitter and Spotify?
So I opened up the "Amazon Music" .ipa file (it's basically just a .zip file you can unzip) and in the app's Info.plist file I see a URL scheme that the app answers to:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.amazon.mp3</string>
<key>CFBundleURLSchemes</key>
<array>
<string>amznmp3</string>
</array>
</dict>
</array>
Unfortunately, this is not a public scheme. That is, there's no documentation available for it that can be googled (or I would have expected to have found it on a page like this).
This means you will probably have do additional research to figure out what kind of parameter to pass along with the scheme. For example, on this page I see a potential parameter of "fb164734381262". Perhaps it's a mp3 file identifier?
My application is a little different, but may be helpful. I am using the Workflow app to automate several things. I can interact with the Amazon Music app through the URL below.
https://music.amazon.com/playlists/B0797C4SN9?do=play
When the URL is opened in Workflow, it causes the Amazon Music app to open. A specific playlist is opened, then it starts playing.
You can create others by opening the app, sharing the playlist to notes. Deleting all of the information after the ? from the URL. Then add do=play to the end of the URL.
I think this would apply to songs and albums as well.
I would really like to know how to get the shuffle playlist from URL, so if somebody figures that out, let me know.
The answer by #Kyle365 works with iOS Shortcuts as well, was able to play a private and public playlist by copying the playlist’s url (share > copy) and changed the url to include ?do=play at the end. I created a shortcut that opens this url and Shortcuts recognizes the url as an Amazon Music url and opens it directly in the Amazon Music app and starts playing it.
Example of Url:
https://music.amazon.com/user-playlists/somePlaylistId?do=play