Safari View

Safari View

by Corona Labs

View and activate on the Corona Store

The Safari View plugin lets you display a web page popup using the SFSafariViewController, introduced in iOS 9.

Documentation

Michael: Thanks!

Unfortunately there is a problem with Corona’s implementation of Safari View Controller affecting all apps that support rotation. If a user:

  1. Opens a web page from a Corona app in the SVC

  2. Rotates the device

  3. Returns to the Corona app by tapping “Done”

The Corona runtime does not send a resize event , so the app’s listeners to relayout the screen do not fire. Worse, the app is left in a bizarre state: the system.orientation variable will correctly say it’s in, say, landscape mode but the display.contentHeight will insist it’s in portrait mode. 

Corona should fix this by checking for orientation change upon returning from the SVC.

Thanks.

Bug is filed: Case 43199

Hi @corona273,

I did a little testing on my side. I’m seeing (as you report) that no “resize” event is sent while the SV is open, but why would you expect that to occur? Also, when the SV is closed, I’m seeing the correct and expected values for “system.orientation” as well as “display.contentWidth” and “display.contentHeight”.

In other words, if I implement a basic “resize” event listener, and print out those 3 values, the behavior is the same when I rotate the phone around both before the SV was ever opened, after the SV has closed, and if (or if not) the phone was turned while the SV was open. The values are completely consistent for me.

Now as for detecting a “resize” event, I’m not sure this should actually happen at all upon closing of the SV. Presumably you use the “resize” event to re-orient your app UI, so why not just call the resize listener function manually when you get a “event.action” of “done” from the SV listener? In my tests, all of the values you need would be correct, so you could use them to re-orient the UI as normal.

Best regards,

Brent

Brent: Thanks for your reply. This Corona bug is a serious problem. I see I’m not explaining it well, and the Bi-Rite delivery did not gain me the benefit of the doubt! Let me try again.

If a Corona SDK-built app in portrait mode opens a web page in SV, and the user rotates the device to landscape, the app’s canvas does not resize once “Done” is tapped. There is no way for the app to fix this. It is a Corona runtime bug. The Corona runtime display.contentWidth still reports, incorrectly, the old portrait value – it should report the new landscape value. The device is now in landscape mode! Even if the Corona app tries to repaint the screen, it cannot because it is has the incorrect values for display.contentWidth and display.contentHeight.

If my second try above didn’t work, I will try a third time with a simple modification to your SV sample code. I trust you agree that if system.orientation is reported as portrait on a phone, the height should always be greater than the width? :slight_smile:

function safariListener(event) if event.action == "done" then if (system.orientation == "landscapeLeft" or system.orientation == "landscapeRight") and display.contentHeight \> display.contentWidth then print ("fatal error: corona runtime says device is landscape but canvas is portrait") elseif (system.orientation == "portrait" or system.orientation == "portraitUpsideDown") and display.contentHeight \< display.contentWidth then print ("fatal error: corona runtime says device is portrait but canvas is landscape") else print("no error") end end end

But if you run this and rotate when the SV is active, you will get fatal errors after tapping “Done”.

This is a trivial fix on your part. The Corona runtime simply needs to adjust the canvas size after SV closes post-rotation.

Hi @corona273,

This is the code I was testing with. I don’t know what your addition of comparing content height > width and vice-versa is for… I merely am checking the reported values of 3 properties on the “resize” event. Perhaps I’m not seeing something obviously wrong in my code?

[lua]

local widget = require( “widget” )

local function safariListener( event )

   if ( event.action == “failed” ) then

      print( “Error loading the URL” )

   elseif ( event.action == “loaded” ) then

      print( “Page loaded!” )

   elseif ( event.action == “done” ) then

      print( “Safari view closed” )

      print( system.orientation )

   end

end

local function onResize( event )

   print( “RESIZE EVENT!!!” )

   print( “ORIENTATION:”, system.orientation )

   print( “CONTENT W/H:”, display.contentWidth, display.contentHeight )

end

– Add the “resize” event listener

Runtime:addEventListener( “resize”, onResize )

local popupOptions =

{

   url = “https://coronalabs.com”,

   animated = true,

   entersReaderIfAvailable = true,

   listener = safariListener

}

– Check if the Safari View is available

local safariViewAvailable = native.canShowPopup( “safariView” )

if safariViewAvailable then

   local sfButton = widget.newButton

   {

      x = 160,

      y = 420,

      width = 160,

      height = 50,

      label = “Safari View”,

      labelColor = { default={1,0,0}, over={1,1,1} },

      fontSize = 30,

      onRelease = function() native.showPopup( “safariView”, popupOptions ); end

   }

end

[/lua]

Brent: Thanks for your reply! The problem is your code does not test for the bug, so it cannot identify it.

Fortunately testing for it is an easy fix. Simply move your existing print statement up a few lines so it’s in your SafariView listener:

&nbsp; &nbsp;print( "CONTENT W/H:", display.contentWidth, display.contentHeight )

On my iPhone 6 Plus, when I go to SV in portrait mode and click “Done” while still in portrait mode (that is, no orientation changes):

Oct  7 20:06:23 SafariViewB[12460] <Warning>: portrait

Oct  7 20:06:23 SafariViewB[12460] <Warning>: CONTENT W/H: 320 480

When I go to SV in portrait mode, rotate to landscape mode, and then click “Done”, I also get:

Oct  7 20:06:49 SafariViewB[12460] <Warning>: landscapeLeft

Oct  7 20:06:49 SafariViewB[12460] <Warning>: CONTENT W/H: 320 480

I’m not sure how the Corona canvas can be 320x480 (that is, taller than it is wide) while in landscape mode. :slight_smile:

The answer is it cannot. This is the Corona SDK bug I’m describing. When the SV controller is closed, the Corona runtime needs to check for orientation changes and change the canvas size accordingly.

Our lua code can redraw the content, but it cannot change the canvas size. The Corona runtime environment needs to do that. The fact that display.contentWidth and display.contentHeight return the identical values in portrait and landscape mode on an iPhone 6 Plus – which should never happen – is a bug. Hoping you can fix this soon!

I have submitted a full .tar.gz project as new bug 43204.

BTW I should add that my original report above focused on the lack of the resize event, which isn’t actually necessary (we can test for orientation changes ourselves in our SV listener and redraw if necessary). So it may have sent you down the wrong path. The problem is that the Corona canvas maintains the portrait dimensions when the device has changed orientation to landscape while the SV controller was active.

Hi @corona273,

Thanks for the clarification. I’ll prompt the engineers to see if they can (easily) fix this. In the meantime, it seems that calling your resize listener after the SV closes is a viable solution, correct?

Brent

it seems that calling your resize listener after the SV closes is a viable solution, correct?

Brent, thanks for your response. No, calling the resize listener after the SV closes is not a viable solution – it will simply repaint the existing screen. That is why this is a significant Corona SDK bug.

The reason it is not a viable solution is because the canvas that Corona runtime provides to our lua app has not been resized. The Corona SDK needs to resize the canvas. Look at my example from last night based on print statements after tapping “Done” in SV:

With no rotation in SV:

Oct  7 20:06:23 SafariViewB[12460] <Warning>: portrait

Oct  7 20:06:23 SafariViewB[12460] <Warning>: CONTENT W/H: 320 480

 

With rotation in SV:

Oct  7 20:06:49 SafariViewB[12460] <Warning>: landscapeLeft

Oct  7 20:06:49 SafariViewB[12460] <Warning>: CONTENT W/H: 320 480

 

The Corona runtime environment failed to resize the canvas – more generally, it should never provide us with a 320x480 canvas when an iPhone is in landscape mode. That is a bug. That is what your developers need to fix.

The correct behavior should be to provide us with a 480x320 canvas if rotation to landscape happens while SV is active.

Put another way, when an iPhone is in landscape mode, the canvas should never be taller than it is wide! But it is. This is the bug. There is nothing we can do about it. Corona staff needs to fix it.

Hi @corona273,

Just to confirm, you should have received a response to your bug report that this issue is fixed and will apply in upcoming daily builds.

Brent

Brent: I haven’t downloaded and tested today’s daily build yet, but this looks promising:

  • iOS: checking for pending resize or orientation evente when returning from other fullscreen views (casenum 43204 , casenum 43199)

 

 

Thank you!

Michael: Thanks!

Unfortunately there is a problem with Corona’s implementation of Safari View Controller affecting all apps that support rotation. If a user:

  1. Opens a web page from a Corona app in the SVC

  2. Rotates the device

  3. Returns to the Corona app by tapping “Done”

The Corona runtime does not send a resize event , so the app’s listeners to relayout the screen do not fire. Worse, the app is left in a bizarre state: the system.orientation variable will correctly say it’s in, say, landscape mode but the display.contentHeight will insist it’s in portrait mode. 

Corona should fix this by checking for orientation change upon returning from the SVC.

Thanks.

Bug is filed: Case 43199

Hi @corona273,

I did a little testing on my side. I’m seeing (as you report) that no “resize” event is sent while the SV is open, but why would you expect that to occur? Also, when the SV is closed, I’m seeing the correct and expected values for “system.orientation” as well as “display.contentWidth” and “display.contentHeight”.

In other words, if I implement a basic “resize” event listener, and print out those 3 values, the behavior is the same when I rotate the phone around both before the SV was ever opened, after the SV has closed, and if (or if not) the phone was turned while the SV was open. The values are completely consistent for me.

Now as for detecting a “resize” event, I’m not sure this should actually happen at all upon closing of the SV. Presumably you use the “resize” event to re-orient your app UI, so why not just call the resize listener function manually when you get a “event.action” of “done” from the SV listener? In my tests, all of the values you need would be correct, so you could use them to re-orient the UI as normal.

Best regards,

Brent

Brent: Thanks for your reply. This Corona bug is a serious problem. I see I’m not explaining it well, and the Bi-Rite delivery did not gain me the benefit of the doubt! Let me try again.

If a Corona SDK-built app in portrait mode opens a web page in SV, and the user rotates the device to landscape, the app’s canvas does not resize once “Done” is tapped. There is no way for the app to fix this. It is a Corona runtime bug. The Corona runtime display.contentWidth still reports, incorrectly, the old portrait value – it should report the new landscape value. The device is now in landscape mode! Even if the Corona app tries to repaint the screen, it cannot because it is has the incorrect values for display.contentWidth and display.contentHeight.

If my second try above didn’t work, I will try a third time with a simple modification to your SV sample code. I trust you agree that if system.orientation is reported as portrait on a phone, the height should always be greater than the width? :slight_smile:

function safariListener(event) if event.action == "done" then if (system.orientation == "landscapeLeft" or system.orientation == "landscapeRight") and display.contentHeight \> display.contentWidth then print ("fatal error: corona runtime says device is landscape but canvas is portrait") elseif (system.orientation == "portrait" or system.orientation == "portraitUpsideDown") and display.contentHeight \< display.contentWidth then print ("fatal error: corona runtime says device is portrait but canvas is landscape") else print("no error") end end end

But if you run this and rotate when the SV is active, you will get fatal errors after tapping “Done”.

This is a trivial fix on your part. The Corona runtime simply needs to adjust the canvas size after SV closes post-rotation.

Hi @corona273,

This is the code I was testing with. I don’t know what your addition of comparing content height > width and vice-versa is for… I merely am checking the reported values of 3 properties on the “resize” event. Perhaps I’m not seeing something obviously wrong in my code?

[lua]

local widget = require( “widget” )

local function safariListener( event )

   if ( event.action == “failed” ) then

      print( “Error loading the URL” )

   elseif ( event.action == “loaded” ) then

      print( “Page loaded!” )

   elseif ( event.action == “done” ) then

      print( “Safari view closed” )

      print( system.orientation )

   end

end

local function onResize( event )

   print( “RESIZE EVENT!!!” )

   print( “ORIENTATION:”, system.orientation )

   print( “CONTENT W/H:”, display.contentWidth, display.contentHeight )

end

– Add the “resize” event listener

Runtime:addEventListener( “resize”, onResize )

local popupOptions =

{

   url = “https://coronalabs.com”,

   animated = true,

   entersReaderIfAvailable = true,

   listener = safariListener

}

– Check if the Safari View is available

local safariViewAvailable = native.canShowPopup( “safariView” )

if safariViewAvailable then

   local sfButton = widget.newButton

   {

      x = 160,

      y = 420,

      width = 160,

      height = 50,

      label = “Safari View”,

      labelColor = { default={1,0,0}, over={1,1,1} },

      fontSize = 30,

      onRelease = function() native.showPopup( “safariView”, popupOptions ); end

   }

end

[/lua]

Brent: Thanks for your reply! The problem is your code does not test for the bug, so it cannot identify it.

Fortunately testing for it is an easy fix. Simply move your existing print statement up a few lines so it’s in your SafariView listener:

&nbsp; &nbsp;print( "CONTENT W/H:", display.contentWidth, display.contentHeight )

On my iPhone 6 Plus, when I go to SV in portrait mode and click “Done” while still in portrait mode (that is, no orientation changes):

Oct  7 20:06:23 SafariViewB[12460] <Warning>: portrait

Oct  7 20:06:23 SafariViewB[12460] <Warning>: CONTENT W/H: 320 480

When I go to SV in portrait mode, rotate to landscape mode, and then click “Done”, I also get:

Oct  7 20:06:49 SafariViewB[12460] <Warning>: landscapeLeft

Oct  7 20:06:49 SafariViewB[12460] <Warning>: CONTENT W/H: 320 480

I’m not sure how the Corona canvas can be 320x480 (that is, taller than it is wide) while in landscape mode. :slight_smile:

The answer is it cannot. This is the Corona SDK bug I’m describing. When the SV controller is closed, the Corona runtime needs to check for orientation changes and change the canvas size accordingly.

Our lua code can redraw the content, but it cannot change the canvas size. The Corona runtime environment needs to do that. The fact that display.contentWidth and display.contentHeight return the identical values in portrait and landscape mode on an iPhone 6 Plus – which should never happen – is a bug. Hoping you can fix this soon!

I have submitted a full .tar.gz project as new bug 43204.