Context
I'm currently trying to design a model generator for hybrid Android apps. The goal is as follows: given any hybrid Android app developed using PhoneGap, generate a UI model that describes the UI states (in this case, I'm treating the UI state as equivalent to the DOM state) and the transitions to these UI states (denoted by actions - e.g., click on DOM element X). The model is represented by a finite state machine, where the nodes are the UI states and the edges are the transitions.
Problem
My current task is to come up with a way to figure out whether a DOM element has an event handler registered to it (let's assume for now that we're only interested in the initial DOM state). With the help of this StackOverflow answer, I was able to come up with a solution that uses webView.loadURL("javascript:" + ....) to determine if an element has an event registered to it either by using, for example, element.onclick, or by using methods provided by libraries like jQuery and Prototype. However, I am currently unable to determine if an element has an event registered to it via addEventListener(), for reasons specified in that same StackOverflow answer. (Again, for simplicity, let's assume we're only interested in events registered right after the page loads, prior to any user interactions).
Questions
The solution I came up with is as follows. I created a new CordovaWebViewClient
(passing the same activity and webView object to the CordovaWebViewClient
constructor) in which the onPageStarted()
method is overriden. The onPageStarted()
code will execute once an HTML page in the hybrid app has begun loading. The overriding code does the following:
onPageStarted()
's parameters, so you can retrieve it by simply accessing the value of this parameter. Example: If the HTML file is located in assets/www/foo.html, the relative URL is www/foo.htmlactivity.getAssets().open(relativeUrl)
, where activity
is the current DroidGap
activity and relativeUrl
is the relative URL found in the previous step.Document
object (I used Jsoup to do this).String
object) and insert that new JS code as part of a new script tag in the Document
object. (In my case, I inserted the new script tag at the beginning of the HTML's head
element)Document
object into a String (say we call this string newHTML
), and call the loadDataWithBaseURL()
method as follows: webView.loadDataWithBaseURL("file:///android_asset/www/", newHTML, "text/html", "UTF-8", null)
. This essentially reloads the page, albeit with the instrumented code included.I then set this extended CordovaWebViewClient
as the webView object's new webView client (using the webView.setWebViewClient()
method). Finally, I called webView.reload()
so that the web view client change above takes into effect. As a result, each time a new HTML page loads in the web view, the onPageStarted
code I wrote would execute.
Note that since item #5 above uses "file:///android_asset/www/ as the base URL and the HTML is loaded by string, you should also include a check at the beginning of your overriding onPageStarted()
method to make sure that the URL of the page that just started loading is not equal to the base URL (i.e., check that the URL is not exactly equal to file:///android_asset/www/). Otherwise, you'll encounter an infinite loop. (I also directed the onPageStarted
not to execute whenever the url does not begin with file:///android_asset, which is the expected base folder).