Remote debugging an embedded WebView in Android

And there I was, thinking that I was done with AzureStorageExplorer for Android v1.0.0. But, nope. In my last round of testing, I couldn’t even login using my work account. The Sign In button didn’t do anything. I went back a few versions to see if the Android update for WebView could have done something to break it. That wasn’t it. The OAuth client library I was using had the recommended code for enabling Javascript in the WebView client so I knew that wasn’t it. I was able to login through the Azure OAuth flow using my personal Azure account. So, I knew there was something about the enterprise account login screen, which could have changed recently that ended up breaking the authentication in the app. It turns out that it did. Read on to know how I found out.

The first step was to prove that something was indeed broken in the login screen for enterprise accounts in Azure in embedded WebViews. To do this, I looked up Chrome’s remote debugging options and found this page describing how to remotely debug WebViews in mobile apps. So, I enabled the setting as recommended by Google, which required adding this piece of code in my activity’s onCreate(Bundle) method.


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}

I ran the app, launched Chrome’s Developer Tools, and connected to the app’s WebView. This is what I found..

2016-12-26_09-49-21

That last error in the console is what was logged when I pressed the Sign In button after entering my work account credentials for Azure. It turns out that the page’s JS now has code to store something in the browser’s localStorage. The reason this isn’t a problem, if you were logging into Azure through a desktop or even a mobile browser, is because localStorage is enabled for every site by default in the non-embedded browser view. But for a WebView in an Android app you need to explicitly enable the DOM storage, just like you need to enable JS through the WebSettings class.

After finding this, it was easy to know where I needed to make the fix. So, I set out to fork the source repo of the OAuth library I was using, made the necessary changes and created a pull request. If you are using the same library and have run into this issue, you could clone my repo and build the project to produce the patched .jar (or an .aar), which you can use in your project directly until the author of the library can get to my pull request (if at all!).

Advertisements

left-right

I created a new public repo on my GitHub page. Check it out.

iOS Style Scroller For PhoneGap App

I have moved the files to GitHub at https://github.com/praneetloke/SpinningWheel-Wrapper

I am going to show you the extensions I made to the spinningwheel script created by the developer of the popular iScroll script. The spinningwheel script by Matteo works great just out-of-the-box. It’s much better than mobiscroll. Spinningwheel allows you to add slots of custom data which means if you are about to use spinningwheel for a date picker then you have to write your own logic for handling the days/months logic and then there’s the leap year calculation for February. But working with spinningwheel was easy and interesting. Matteo’s code is always organized as you can see from the source of his iScroll and SwipeView scripts. It was just a matter of writing down what extensions I wanted to make to his script. So, I first started out by realizing that I wanted a wrapper around the spinningwheel; that’s where the second file in the attachments comes to use. Most importantly his scripts are always written in regular javascript and always has a destroy method (which is very useful when you want to manage memory). Writing in regular javascript means no external dependencies. Following the same guidelines I too made the extensions in regular javascript and also the new events you can subscribe to in the spinningwheel are written in regular javascript. Another advantage of using spinningwheel over mobiscroll is spinningwheel uses translate3d for the transitions which means it will look and work awesome on iOS devices and even on higher end Android devices (phones and tablets). Oh and another one again is that since spinningwheel is written in regular javascript it easy for you to make extensions to it based on your needs unlike mobiscroll which relies of jQuery selectors heavily which means if you are not using jQuery, good luck!

The ScrollWheel class I wrote allows you to use the SpinningWheel instance as a singleton object. You can create an instance of ScrollWheel and pass in parameters like ‘date’, ‘time’ or ‘custom’ (if you want to use custom slots). Most of you would want to use the date and time presets that I created. The custom presets allow you to simply bind a click listener to text input and show the spinning wheel without having to do any extra work.

As you will see in the ScrollWheel.custom file, I have set the cancel action to call the post callback (which you would have passed when an instance of ScrollWheel was created) immediately and a null value for the results. In your post callback be sure to add a check for the results array so you don’t accidentally update the existing value in the text box (if any) to null. You can see what I have done with my post callback in ScrollWheel_Init.

The HTML element that you need to have to actually show the spinningwheel is pretty simple. Just use something like this (or exactly):

<input id=”timePicker” type=”text” readonly=”readonly” onfocus=”preventFocus(this)” onclick=”showTimePicker(event, this.id, this.value);”/>

or you can modify the showTimePicker function to take just the event object as a parameter and modify the click handler in the element to:

<input id=”timePicker” type=”text” readonly=”readonly” onfocus=”preventFocus(this)” onclick=”showTimePicker(event);”/>

Or you could alternatively ‘bind’ to the click event using jQuery or Zepto as well. I will not explain the logic of updateDates since it is pretty straight forward. In spinningwheel.js, you will find that I have added a new event handler that you can set via an instance of ScrollWheel (or directly via SpinningWheel) called scrollEndAction. This is what you need to set if you want to subscribe to the scrollEnd event and have a handler invoked every time the user stops scrolling a slot.

A snippet of the handleEvent function in spinninwheel where I added the invocation of the scrollEndAction

else if (e.type == ‘touchend’) {

if (e.currentTarget.id == ‘sw-cancel’ || e.currentTarget.id == ‘sw-done’) {

this.tapUp(e);

} else if (e.currentTarget.id == ‘sw-frame’) {

this.scrollEnd(e);

//console.log(“calling scroll end action”);

setTimeout($.proxy(this.scrollEndAction(this.activeSlot), this), 100);

var self = this;

setTimeout(function () {self.scrollEndAction.apply(this, [self.activeSlot]);}, 100);

}

}

There are two new public functions I have added to the spinningwheel.js, called showSlotValuesAfter and hideSlotValuesAfter. These functions will allow you to pass the slot index (0 based), the last key of the json object that the slot holds as values, and the number of values you want to show/hide after that last key. The reason for these is to help with hiding the dates that don’t apply for a particular month and then showing them again when they are applicable. Look at updateDates to understand how this is done. I have also made sure that when you call on these functions the corresponding slot’s max scroll boundary is updated so that it doesn’t allow you to scroll over the ‘hidden’ values. Find out why I call them ‘hidden’ values. 

The good thing about the wrapper I have written is that it checks if an instance of a ScrollWheel is already open and if so it won’t allow you to open another one. This was the only problem with spinningwheel out-of-the-box. SpinningWheel is a global instance and you have to manage it. If you open too many instances at the same time you are likely to chew up memory from the browser and can see significant impact to the performance of the page and even states and values will be corrupted. This is why I wrote the wrapper to make sure that I take care of this.

There is no technical reason for me to name the wrapper as ScrollWheel so you can change the name of the class to whatever you like. Just remember to retain the names and the original license at the top of the files. Although I claim no responsibility for the stability of these extensions and no support for them, I do know that they work because I use them and you can ask me for help as long as you don’t blame me for anything after all you downloaded them, I did not force you to.

A word of caution about spinningwheel’s goal. It is to be used with webkit based browsers. It was created to be used with iOS and Android phones as they implement the WebKit framework and also it is original intended to be used with touch enabled WebKit platforms which means it will not work with desktop browsers (Chrome, Safari, or Opera) out-of-the-box but there’s good news, download the touché framework I blogged about last week and it should work like a charm. I may look into porting this for the WP7 but not yet. I’ll tackle that when I get there but if you do be sure to let me know. It’ll save me some time 🙂

Be sure to ask me if you don’t understand the sources. Just don’t be a duck about it. That’s it for now. Enjoy your new spinningwheel!