native.showPopup() does not return to my app when...

I just took a quick look at our WebView code on Android.  Your Lua listener will receive an error code if it fails to load the URL.

   http://docs.coronalabs.com/api/event/urlRequest/errorCode.html

So, what you should do is check if “event.errorCode” is *not* nil as shown in the link above.  If you did receive an error code, then you can either reload your webpage with your local HTML file… or call the webView:back() function.

I hope this helps.

Hi Joshua, 

Thank you very much for looking into what my options could be. I tried your suggestion and find that I can detect the error but still end in that page. Perhaps its once again the speed at which this thing is going through. My listener triggers are a little interesting though. See below output from my logcat and my commentary (marked as ^^ ). Sorry for the length of this.

I/Corona  (29621): Event type & URL is     other file:///data/user/11/com.appynerds.xxx/app_data/infoFinal.html

^^ above, first time the listener is called for initial load request. Event type is other.

I/Corona  (29621): Event type & URL is     loaded file:///data/user/11/com.appynerds.xxx/app_data/infoFinal.html

^^ above, second time the listener is called for initial loading of my local html. Event type is loaded.

I/Corona  (29621): Event type & URL is     link http://appynerds.com/index.php/contact

^^ above, I tap on the fake link pointing to my contact page. This is what I want to trap. Now the internet is off so this is supposed to return an error. Event type is link.

I/Corona  (29621): Event type & URL is      http://appynerds.com/index.php/contact

^^ above, fourth time the listener is called. event type is blank. URL is the last link tapped now coming back with an error. So far so good.

I/Corona  (29621): error code     -2

^^ further down in my listener I check for error and print the code. Still the same listener call (ie fourth time it is running)

I/Corona  (29621): Event type & URL is     history file:///data/user/11/com.appynerds.xxx/app_data/infoFinal.html

^^ in my error trap I call webView:back. What you see above is the 5th time the listener is called. How the event type is history and url is my original local html. 

I/Corona  (29621): Event type & URL is     loaded http://appynerds.com/index.php/contact

^^ Now this is bizarre… All was good until the 5th listener trigger and I was expecting to land in my original html page with an event type of loaded. I end up with a loaded for my contact page which gave me the error in the first place. Since internet is down I also end up with the Android’s page not loaded message. Yikes. 

So this 6th triggering of the web listener going back to the error page instead of obeying the webView:back is something I need to understand a little more and avoid if possible. 

Any thoughts? 

Yeah, that’s why I was thinking it might be better for you to reload your local HTML when an error is detected.  That may be more reliable than going back a page.  I’m think of the case where the WebView quickly loads more than one error page back-to-back.  That’s what I think is happening.

Yup. This is working better. I can see the error page briefly flash in between but I do end up where I need to. Given the offline is not a common use case for someone wanting to hit my email link I think its a safe bet that I can live with this solution. Thank you so much for your help.

Last question. Is there a way to reset back/forth history in the webView? Reason I’m asking is that, in this case we’ve been discussing, once user hits the email link and comes back to the initial page I still get my “Back” button visible since webView.canGoBack is true at this point. What I need to do is to somehow get webView know that I’m reloading my initial html so therefore there is no Back to go to. In this case if you hit back you end up going to the sendmail link. 

I think I can look at the URL and not make the back button visible if I’m on the initial html so I can deal with this programmatically but just asking if I could get webView.canGoBack reset. 

Thanks!!!

>> Last question. Is there a way to reset back/forth history in the webView?

Unfortunately no.  The only solution I can think of is to destroy and re-create the WebView, which is a bit heavy handed.

I also don’t recommend that you call the webView:back() function multiple times in a loop either because it performs that operation asynchronously, meaning that the canGoBack property won’t update until after the back operation finishes loading the previous page.

That said, I’ve seen a Corona developer destroy and re-create a WebView to reset the navigation history before.  What he did was create his own loading object made up of a white rectangle a text object that was positioned behind the native WebView.  This way it doesn’t look like the WebView quickly disappears and re-appears to the end-user, which would look ugly.  I also think he hid the WebView when loading a webpage on the Internet and then showed it once it finished loading via its Lua listener… which came in handy for websites that take a long time to load.  This was especially useful since the native WebView doesn’t actually show any load progress so that the end-user won’t think something is wrong.

Got it. I will deal with it. I think, rather than destroying and recreating the webView, better option for me is to trap the URL for initial html and when it is loaded simply hide the back button. Normally, the back button is not offered on that page because it happens to be the very first page but only in this unique case, where I have to send the user back to the initial page then I will simply hide the back button. 

This thing is wired to the teeth so I bet it will break in future as Google gets webView issues improved. Till then its as good as it gets. Thanks much for hanging in there with me on this one. I appreciate it. 

Happy to help!  It’s always good to know how some of our features are being used in real world apps.

Indeed! Thank you very much for not simply telling me to “Submit a feature request” and brushing me aside but rather trying to find a way to make this thing work as best as it can. Most appreciated. 

Excellent informative thread guys.  Joshua thanks for digging into the code and getting out the details too!

Turns out for some weird reason, webView:stop() does not work when the link clicked is a mailto: link. It works for all other links that would have opened the link inside the webView itself but mailto: that sends you to the native app at OS level can’t be stopped with webView:stop(). Since apparently I wasn’t able to stop the webView sending me to the native mail app I wasn’t able to even get the native.showPopup(“mail”, options) to show. Managed to solve it using a little hack… Here goes… 

Since I have control over the html help file I simply changed the mailto link to a regular link while keeping the abc@xyz.com as the visible link text. I simply placed “test” as the link URL into my HTML. In my webView listener I listen and check the URLs as they get clicked. I look for “test” inside the URL clicked. If I find it I call webView:stop() and then call native.showPopup(“mail”, options) instead. 

This is now working and I am able to get back to my webView scene after the mail is sent. Hope this helps others who might be stuck with the same thing in time to come. 

Regards,

Kerem

Nice workaround :slight_smile: I was going to suggest something similar but I saw you already solved it.

Thanks. I hope the API can be fixed so that webView:stop() will actually stop the loading of a mailto: link as well. This is the only way to get a consistent UX in the cases where app user goes to third-party web pages where we don’t control the way links are built. 

The webView:stop() function can only stop the loading of web pages.  Tapping a mailto:// link causes the WebView to launch your device’s default mail app (not a popup), which is not a web page.  That’s why the webView:stop() function won’t stop it.  And since the mailto:// is launching your Mail app, that’s why your trapped in that app.

If you want the end-user to remain in your app, then the solution is to set up a Lua listener to trap the URL request for the mailto:// URL scheme and return true to override iOS’ default behavior.  That’s your opportunity to display a mail popup within your own app via the native.showPopup().  This sounds like what you’re doing now, which is the right solution.

Just note that Android’s WebView behavior is completely different.  Android’s native WebViews will not display the mail app by default when tapping a mailto:// URL scheme.  Instead, the WebView will attempt to load the mailto:// as a webpage, which of course will fail and display an error page in the WebView instead.  So, on Android, you have no choice but to override the URL request and implement it yourself.  This is actually how it works at the native level on Android.  Unfortunately, even if you do override the URL request, you’ll still see a failed to load webpage flashed onscreen.  There really isn’t a nice way to handle this on Android, which makes what you’re doing overly difficult.

Hi Joshua, 

Thanks for your input and help. I will try “return true” in my URL trap for “mailto”. I didn’t think of return true to stop the webView from loading the external mail app so I created this “broken link” hack which meant the webView could not load anything and I was able to trap this and trigger the native.showPopup etc. Your idea should make for a more refined solution and would probably get rid of that one blink I’m getting when user taps on the broken link.

So it sounds like this solution is the only way to deal with this issue on Android as well. Will test later today and report back.

Once again thank you very much.

Regards,

Kerem

Hmmm. You were absolutely right. My hack works well on IOS but not on Android. webView on IOS discards the bad URL, blinks and moves on. On Android it brings up a message telling me that my URL is broken. 

So I will improve my listener with the return true in addition to the “broken URL” hack. Fingers crossed.

Thanks once again for your help.

Ok. On Android return true or webView:stop() still does not limit the loading of the error page. Funny thing is how my url is no longer a mailto but still gets through webView:stop(). Problem is that once I return from the mail app the error page is there. I will try to detect when I’m on Android and reload the original help HTML file in the meanwhile. If you have any ideas to make this look a little better or get more straightforward I’m all ears. Thanks much!!!

Joshua, I re-read your post above and you clearly mention return true is the way to override that URL request on IOS. Is there a similar way to override the request on Android? I’m ok with the brief flash of that message as long as I can throw it away and return to the original html. Thanks

Found a way. One hack brings on another one… I found that if I throw a webView:back() into the URL trap and make it conditional on Android I see the flashing error page but I end up back in my caller html. All good. Thanks for your help.

Edit : Throws hands in the air while running around the room… No joy… 

I’m sorry.  I had it backwards.  You need to return “false” from your urlRequest to override the request.  Returning true (or not returning a value at all) tell its to go ahead and load the URL.

   http://docs.coronalabs.com/api/library/native/showWebPopup.html#example

Our sample app “Interface/WebOverlay” that is included with the Corona Simulator shows an example of this.  There is a “corona:close” URL in the HTML which when tapped on will be overridden by the “main.lua” to close the web popup.

Ahh there you go. I know you were testing me and I failed!  :slight_smile:

Thanks much for the follow-up. This will be ok I’m sure.