Inconsistent execution of executeScript in Cordova inAppBrowser on iOS - javascript

I'm having some trouble with some inAppBrowser behavior in my cordova app. Here's the code:
var codePass = fooCode;
var executeScriptFunc = function(event) {
ref.executeScript({
code: codePass
}, function (value) {});
ref.removeEventListener('loadstop', executeScriptFunc);
};
var ref = cordova.InAppBrowser.open(fooObject.link, "_blank", "location=yes,enableViewportScale=yes");
ref.addEventListener('loadstop', executeScriptFunc)
The strange thing here is that the code works perfectly every time when emulated. It opens the browser and executes the script no problem. But when I try it on my actual iPhone device, it doesn't always work. The script executes maybe every other time. But it's never even that consistent.
Both the emulator and iPhone are using iOS 9.3.4. Any ideas?

If the site inside the inAppBrowser happens to be served via HTTPS, the callback for executeScript() will not work if the site employs a Content-Security-Policy HTTP response header that does not contain the gap: or gap-iab: schemes for the default-src directive. These are needed because execution of the callback function on iOS relies on an iframe that gets added to the page.
You can check whether this is the root cause for the problem by opening Safari’s Web Inspector for the inAppBrowser—it has a separate Web Inspector instance, independent of the parent application that opened it—and look out for a corresponding error message in the console. Note that you should open the console before executeScript() is run, or otherwise you might not get the error message.

Make sure also that you don't have other event handlers firing at the same time during your polling.
I had multiple pollers all firing every second and that's when I ran into the issue.
After changing the polling time so they all fired at different times, the issue went away.

Related

Vue-fullscreen error with user-generated event

I am using the vue-fullscreen plugin to trigger a fullscreen of an element in my code. I am calling the function using #click, yet despite that I am getting the following error:
Firefox:
Request for fullscreen was denied because Element.requestFullscreen()
was not called from inside a short running user-generated event
handler.
Chrome:
Failed to execute 'requestFullscreen' on 'Element': API can only be
initiated by a user gesture.
As per threads like the following, Javascript request fullscreen is unreliable, I have have found the following warnings:
Make sure it is generated directly by a user click.
I think I am.
Make sure there is not more than a 1 second delay between the user generated action and the function.
I find no delay, especially given the function is incredibly short and direct.
If you are using iframes, make sure you allow fullscreen parameters, including in any parent iframes.
I am not using an iframes.
Here is a snippet of my code:
HTML:
<div class="tool_circle_button" #click="toggleFullscreen"></div>
<fullscreen :fullscreen.sync="fullscreen">
Content
</fullscreen>
Javascript:
toggleFullscreen () {
console.log(this.fullscreen)
this.fullscreen = !this.fullscreen
},
Do these errors suggest that the #click command is not being recognized as a user-generated click? If not, what else could be causing this? Thanks so much for your help!

Cordova inappbrowser fails to load page

I am trying to create a OAuth login flow. In a Cordova app (tested only on Android), I try to load a page from my server which redirects the browser to the correct OAuth page on google's side. However, this abruptly stopped working.
If you try the url in the code below in a browser, you may want to go incognito or try some other measure to avoid autologging in. (The server creates an account to an indev service if you actually log in.)
If I write the code like this (I omit the fishing of the credentials tokens from the URL, this is the simplest reproducible example.):
function onLoad(){
document.addEventListener("deviceready", onDeviceReady, false);
}
function onDeviceReady() {
var authWindow = cordova.InAppBrowser.open("https://dev.taskapp.io/googleURI", '_blank');
authWindow.addEventListener("loadstart", function(e){
alert("Loadstart fired")
}
)
}
The webview remains empty and the message Loadstart fired appears once. If I swap '_blank' to to '_self' or '_system', the pages load and the redirects work but the events never fire. This happens only with the given page.
I am at my wit's end.
Update: the same code works like a charm on iOS. On android using window.open() also fails.
Update 2: I now understand, that _system opens the os's browser, which I obviously have no control over and that _self squishes whatever was in the webview, rendering my listeners to nothingness. _blank works once from a cleanly cloned repository and then breaks on a second build (without code change).
If I substitute the url in the cordova.InAppBrowser.open(...) to the one my server redirects from, Google's tech loads. However the final login button (which would trigger the redirection to my server, one can assume.) is dead.
Does redirecting the _blank target break things? Is this a bug? Is someone else experiencing this?

HashNavigation in cordova wp8 hangs app

I have next code
function navigate(_hash){
alert('before');
//try#1
window.location.hash = _hash;
//try#2
// window.location.href=window.location.href.split("#")[0]+"#" +url;
alert('after');
}
navigate('someurl')
the issue is that after changing url hash (both variants) app just hangs. And interesting thing that second alert is not firing. so app just... crashes after some time.
Nothing in js console.
Debug log says
The thread 0x*** has exited with code 259 (0x103).
google found nothing on that. Seems like this is acommon error code.
More details:
i'm using ChaplinJs so just can't get away from hash navigation.
second thought was that chaplin overloads system and we caanot get anywhere, but(!) putting logs and alerts in source of lib in window.on('hashchange',....) also didn't make any effort because we do not get there also.
WP 8.0
tried both Cordova 4.* and 5.*
also tried to modify xhrXelper.cs but it is not related tonavigation itself.
PS: I know that jquery mobile suggests to disable hashchanges onmobile navigation. But i can't :(
PPS: also tried todisable chaplin haschanges
new App({routes: routes, controllerSuffix: '-controller', pushState: false,hashChange:true})
but this also didn't make any good results because it's placing hash to href to check it in interval and app hanged again. So i assume that is a webview problem
More additional info:
continious re-run of app makes it work sometimes (1 run of 10 can make it work). That's very strange.
Emulator and device behave in the same way.
Update: Read somewhere that it's critical to restrict navigting before "deviceready" event.
But this is also not a case.
Update2: create cordova proj from scratch. Added hash change indeviceready cb and it hangs
Update3: same code on 8.1 works perfect

Chrome App messaging and 'loadstop' vs. .load() timing

I am developing a Chrome App with webviews. Pages intended for the webviews may also run in a regular browser. If inside a webview, pages send messages to the main App, but apparently they need to get a message from the App first, in order to know where to send their messages.
No problem - the main App sends a message as soon as it sees a 'loadstop' event which tells the pages where to send messages to. If a page is not in a webview then it never gets the message.
The problem is, I need to know when a page should stop waiting for the message and assume it is NOT in a webview.
When does 'loadstop' occur, relative to events in the page such as jQuery's .ready or .load? Is there a way to trap or trigger an event guaranteed to occur after 'loadstop' MIGHT be seen in the main App and a message sent and received by the webview's JavaScript.
When does 'loadstop' occur, relative to events in the page such as jQuery's .ready or .load?
According to the documentation for the loadstop event:
Fired when all frame-level loads in a guest page (including all its subframes) have completed. This includes navigation within the current document as well as subframe document-level loads, but does not include asynchronous resource loads.
This would suggest it's more akin to jQuery's .ready(), which executes after the DOM tree is loaded, but before waiting for asset (.css, .js) downloads.
Keep an eye on that documentation page; it's already much improved since two weeks ago.
Is there a way to trap or trigger an event guaranteed to occur after 'loadstop' MIGHT be seen in the main App and a message sent and received by the webview's JavaScript?
Your manifest.json declares your my-app-main.js background script (and your webview permission) which launches your my-webview-wrapper.html which includes your <webview> tag and also inlines some javascript (or sources a my-webview-wrapper.js file) that assigns event listeners to your webview via an onload function as such:
onload = function() {
webview = document.getElementById("the-id-attribute-of-my-webview");
webview.addEventListener("<EVENT>", function() {
// the cool stuff you want to do
}
}
<EVENT> can be any of the webview DOM events listed in the documentation I linked (including loadstop). Your main app shouldn't really care that any of this is happening. (It's async! It's javascript! It's magic!)
If you're still confused, just poke around Google's webview sample on GitHub.

Event onBrowserClose for Google Chrome Extension?

I am developing an extension for Google Chrome. My background script, everytime, authorizes on a server that uses the XMPP API, and subscribes for a PubSub node. I need to unsubscribe on the exit, otherwise the dummy subscriptions will remain on the server. Is There any onBrowserClose event in the Google Chrome Extension APIs?
There is no such event in the Chrome Extension API.
There is however a chrome.windows.onRemoved event that fires each time a window closes. I figured you could check in this event if you closed the last window, but unfortunately due to the asynchronous nature of Chrome this doesn't work.
What I tried was running a simple AJAX request in the onRemoved event handler. The AJAX request never got to the server, as Chrome had already closed before running the event (or just disregarded it).
Making the final answer be: No, currently you can't, as far as I know. You might want to star the following bug report at http://crbug.com/30885 to get noticed on updates.
If you catch the case when the number of open tabs is 0, you can treat that as a Chrome onClose event. In my case, I have to cancel a desktop notification before Chrome closes because it was crashing otherwise.
This is how I did it:
1. Initialize a variable num_tabs by using the following:
chrome.tabs.getAllInWindow( null, function( tabs ){
console.log("Initial tab count: " + tabs.length);
num_tabs = tabs.length;
});
2. Increment num_tabs when a tab is created:
chrome.tabs.onCreated.addListener(function(tab){
num_tabs++;
console.log("Tab created event caught. Open tabs #: " + num_tabs);
});
3. Decrement num_tabs when a tab is removed and run your browser onclose event handler if num_tabs = 0
chrome.tabs.onRemoved.addListener(function(tabId){
num_tabs--;
console.log("Tab removed event caught. Open tabs #: " + num_tabs);
if( num_tabs == 0 )
notification.cancel();
});
Adding a browser close event is a pretty frequent request. Star http://crbug.com/30885 for updates. And read the bug report for a clever hack to detect when the browser is shut down via a key press.
This one works for me:
chrome.windows.onRemoved.addListener(function(windowId){
alert("!! Exiting the Browser !!");
});
It takes chrome.windows rather than chrome.tabs.
TL;DR: Try window.onunload event, it works for some cases.
As it was mentioned before we generally can't handle something like onBrowserClose event and prevent browser from closing. But for some cases we can use window.onunload event for doing something synchronously, and it does work if it really synchronously.
From my experience you can at least:
Save some information in (for example logs) in HTML5 localStorage (which is synchronous).
Call some asynchronous chrome extension API functions but you can't get a result. (It works for me! Yay!)
Perform synchronous XMLHTTPRequest (yeah, sometimes it works).

Categories