EddyVerbruggen / cordova-plugin-safariviewcontroller

:tiger: :elephant: :crocodile: Forget InAppBrowser for iOS - this is way better for displaying read-only web content in your PhoneGap app
MIT License
281 stars 143 forks source link

Needs event listeners and executeScript like InAppBrowser #1

Open jacobg opened 8 years ago

jacobg commented 8 years ago

Needs event listeners equivalent to IAB: loadstart, loadstop, loaderror, exit. You could do even more than IAB, because whereas IAB could not access response status code, probably in SVC you can.

Also, need executeScript method to support inter-window communication.

Reference: https://github.com/apache/cordova-plugin-inappbrowser

reicolina commented 8 years ago

+1 to that.

EddyVerbruggen commented 8 years ago

I don't have it planned, but pull requests are of course very welcome.

ghost commented 8 years ago

+1

iliasbhal commented 8 years ago

+100000000

the goal is to use it exactly like the inAppBrowser plugin. with this plugin we everyone would be able to create an outstanding login experience with safari cookies and power :p

one word, it would be EXTREMELY awesome :dancer:

EddyVerbruggen commented 8 years ago

Can you guys point me at the API's Apple has provided to do so? Thanks.

danielstrickland commented 8 years ago

Because SafariView is real Safari and allows access to cookie and other user data, the security is much tighter - things like executeScript and other callbacks aren't supported.

To pass data from SafariView back to your app, use a custom URL scheme: Talk to App

You can use Eddy's CUSTOM URL SCHEME plugin to do that. It just tested both plugins (SafariView and URL Scheme) and they work great together.

EDDY: The one thing that would be nice in the SafariView plugin would be the option to open the browser in the background (i.e. hidden from view).

I'm using it to open a website, read some cookies, use the URL Scheme to pass the cookie data back to the app and then close the browser. This all happens automatically, without user input, and it would be nice to not have the browser window flash in front of the user.

EddyVerbruggen commented 8 years ago

@danielstrickland Thanks for sharing these ideas!

You can't hide a viewcontroller unfortunately. You can hide the view in the viewcontroller but that would show a black canvas. You can quickly hide it but the user will notice.

danielstrickland commented 8 years ago

@EddyVerbruggen

No problem! Thanks for the reply.

I'm not very familiar with Objective-C so you would probably know better than I, but here is a blog post where the author demonstrates a hidden Safari View Controller (near the bottom of the post) and includes a screen capture of it in action:

https://library.launchkit.io/how-ios-9-s-safari-view-controller-could-completely-change-your-app-s-onboarding-experience-2bcf2305137f

EddyVerbruggen commented 8 years ago

Ha, interesting! No code there, but let me think about it for a sec.

EddyVerbruggen commented 8 years ago

Looks like it's going to work. The trick is to set the viewcontroller's view frame to CGRectZero :)

I'll publish a new version shortly.

danielstrickland commented 8 years ago

Awesome!!

The web developer in me was guessing they were setting the view to 1x1 pixels or something... Guess I was pretty close.

EddyVerbruggen commented 8 years ago

Haha, yeah I was wondering the same and sort of translated that to a native approach :+1:

If you can share more details about your cookie trick (code perhaps) so others can benefit than that would be great. A PR to the readme would make the most sense I guess. Only if you have time.

And pick up 1.4.0 while it's hot!

danielstrickland commented 8 years ago

Wow. Impressively quick turnaround.

I'll document some example code for my method of fetching cookies and add to the Readme. Probably later this evening.

Thanks!

conor-mac-aoidh commented 8 years ago

Hi,

First of all, thanks for the great plugin @EddyVerbruggen. I am using many of your plugins in my application, and you've saved me a lot of time!

I've been using the hidden method as described in the Readme to get access to a cookie from Safari. This method is not working for me. I'm on iOS 9.2.1. The Safari View Controller opens correctly, loads the html file from my server, but fails to call back to the app using the URL Scheme (I have verified that the URL scheme standalone is working, and does open the app and is handled properly). Since this is happening in the background, I can't really tell what's going on.. except for this error:

securityd[89] <Error>: SecDbRecordChange db <SecDbConnection rw open> changed outside txn

I added a timeout to call the 'hide' method after 2 seconds if the view fails to call back to the app. Notably, when this triggers, it doesn't actually close the view in safari. I can tell this using the Safari Web Inspector - the page on my server is still open. Additionally, if I subsequently go to login to my app using the Google/Facebook cordova plugins, they fail to load in safari also.

Any ideas of why this could be happening / how to debug the issue further?

Thanks

Conor

EddyVerbruggen commented 8 years ago

@danielstrickland do you see any difference between @conor-mac-aoidh's and your approach regarding communication between the app and SVC?

conor-mac-aoidh commented 8 years ago

Some additional information:

Also, when this is working correctly, after the reboot, after calling the 'hide' method, I can /still/ see the HTML page on my server open via Web Inspector. Not sure why, I would expect it to close when 'hide' is called.

danielstrickland commented 8 years ago

1) You say the Facebook cordova plugin "fails to load" in Safari? Do you mean the Facebook login web page doesn't load at all or once you log in doesn't give control back to your app? The Facebook plugin uses the same method - loading SafariView and then passing back to your app (just not hidden). If that isn't working, then there is a configuration issue with your app.

2) Did you try setting "hidden:false" in the SafariView plugin and debugging your web page by having the javascript write out the different steps? You need to rule out an error in your web page.

conor-mac-aoidh commented 8 years ago

When I say the Facebook/Google login doesn't load, I mean Safari opens, but the page never loads. If I press reload, it still doesn't load.

I did try with 'hidden:false', in this case I get a completely unresponsive UI when I get back into the app - no buttons/inputs are clickable.

I think there is something causing these errors, that needs a reboot to fix, but not sure what.

conor-mac-aoidh commented 8 years ago

Ok after a reboot, I can't actually recreate this issue. I'll post back if it occurs again. Thanks

cvillerm commented 8 years ago

About the original request of this issue, I think that allowing calls to executeScript won't work (by design) and shouldn't work as one of the purposes of SafariViewController is to display an embedded and safe way of browsing. For instance, this is a typical way of implementing a safe login form in which a user can sign in without any risk of having credentials typed stolen (what an executeScript would likely allow), especially when implement Single Sign On. This allows integrating enterprise login in a third-party application, e.g. by implementing a flow that is eventually calling the application back (using a custom scheme) by given it some kind of token (e.g. OAuth access token).

iqmeta commented 8 years ago

@cvillerm you're right about security, if you don't trust the app.

If it's a trusted app, this feature is pretty powerful to integrate (legacy/blackboxes) enterprise endpoints like SAP. Currently this plugin is no replacement when it come to already working inappbrowser scenarios, when it doesn't can do the same.

+1 vote to keep looking if executeScript is still somehow possible / Debugging => console.log would be great too.

I guess Apple is anyway killing old WebViews with newer iOS releases, so it's time to spend more time on (a new hope) inject code via App VPN SSL ReverseProxy Setups.

tomgallagher commented 7 years ago

+1 for me too.

InAppBrowsers are following a similar path to the desktop evolution. Compare something like the 'executeScript' functionality to bookmarklets, so what we need from things like SafariViewController is the opportunity to build extensions. Reviewed and signed and integrated into the browser itself. That would be fine. Extensions in mobile browsers cannot be that far away.

tgensol commented 6 years ago

Any news on that ?

yosigolan commented 6 years ago

Hey. i understand its not possible to fire events from the web page inside the controller to the app. i wanted to ask if there is a way the web page displayed inside the controller will trigger a close action (like pressing the done button). Thanks

gatelli commented 6 years ago

Hi, I'm using safariviewcontroller to oauth with Dropbox. When it's done, Dropbox send token into the url, and I need to store this token. Unfortunately I can't catch it since the url is changing (1st page is the login page, last one is the auth confirmation page). I can get the 1st page url but not the last. How is it possible to work with a kind of event listener, watching the url change ? Thanks... if someone has an idea...

bhumin3i commented 6 years ago

anyone please help me how we get call back URLs. like

  inApp.addEventListener("loadstart", (event) => {
  console.log('event list');
          });
WuglyakBolgoink commented 6 years ago

any news?

tzappia commented 4 years ago

A cautionary note for those wanting to take some of these approaches using the hidden: true option. Apple may reject your app submission if you use a hidden SFSafariViewController. I have not experienced this, but saw this in the documentation today and remembered this feature on the plugin.

Important In accordance with App Store Review Guidelines, this view controller must be used to visibly present information to users; the controller may not be hidden or obscured by other views or layers. Additionally, an app may not use SFSafariViewController to track users without their knowledge and consent.

Source: developer.apple.com