TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and former Developer Advocate with Google now residing in Colorado. Besides tech, I enjoy landscape photography and share my work at ColoradoPhoto.gallery.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 241 other followers

  • Sleepless Nights…

    April 2012
    S M T W T F S
    « Mar   May »
    1234567
    891011121314
    15161718192021
    22232425262728
    2930  
  • Blog Stats

    • 876,139 hits

Enable Geolocation in a WebView (Android)

Posted by David Chandler on April 23, 2012

HTML5 Geolocation lets you access the browser’s location information from Javascript. For a quick demo, visit google.com in a mobile browser and observe your location at the bottom of the page. Geolocation works “out of the box” in the Android browser or Chrome Beta for Android. The first time you visit a Web site that wants to know your location, the browser will prompt you to allow it.

However, if you’re writing an Android app that uses a WebView to display Web content, you must specifically enable geolocation in the WebView in order for pages that use it to work properly. To illustrate, I’ve put together a minimal Android app that uses a WebView with geolocation enabled. The easiest way to use the sample is to create a new Android Project called GeoWebView (package name com.example.webview) and then copy and replace the generated sample code with the files below.

First, the Android manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.webview"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="5" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".GeoWebViewActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoTitleBar" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Only two permissions are required: INTERNET and ACCESS_FINE_LOCATION. This example uses the NoTitleBar theme to display the WebView content full screen.

Next, our layout (main.xml):

<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webView1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />

Not much to it, just a WebView.

And finally, here is the complete app, consisting only of GeoWebViewActivity:

package com.example.webview;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;

/**
 * A minimal WebView app with HTML5 geolocation capability
 *
 * @author David M. Chandler
 */
public class GeoWebViewActivity extends Activity {

	/**
	 * WebViewClient subclass loads all hyperlinks in the existing WebView
	 */
	public class GeoWebViewClient extends WebViewClient {
		@Override
		public boolean shouldOverrideUrlLoading(WebView view, String url) {
			// When user clicks a hyperlink, load in the existing WebView
			view.loadUrl(url);
			return true;
		}
	}

	/**
	 * WebChromeClient subclass handles UI-related calls
	 * Note: think chrome as in decoration, not the Chrome browser
	 */
	public class GeoWebChromeClient extends WebChromeClient {
		@Override
		public void onGeolocationPermissionsShowPrompt(String origin,
				GeolocationPermissions.Callback callback) {
			// Always grant permission since the app itself requires location
			// permission and the user has therefore already granted it
			callback.invoke(origin, true, false);
		}
	}

	WebView mWebView;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		mWebView = (WebView) findViewById(R.id.webView1);
		// Brower niceties -- pinch / zoom, follow links in place
		mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
		mWebView.getSettings().setBuiltInZoomControls(true);
		mWebView.setWebViewClient(new GeoWebViewClient());
		// Below required for geolocation
		mWebView.getSettings().setJavaScriptEnabled(true);
		mWebView.getSettings().setGeolocationEnabled(true);
		mWebView.setWebChromeClient(new GeoWebChromeClient());
		// Load google.com
		mWebView.loadUrl("http://www.google.com");
	}

	@Override
	public void onBackPressed() {
		// Pop the browser back stack or exit the activity
		if (mWebView.canGoBack()) {
			mWebView.goBack();
		}
		else {
			super.onBackPressed();
		}
	}
}

The onCreate() method obtains the WebView and enables Javascript and pinch/zoom. The last few lines before loading the URL google.com are the most important. In addition to calling setGeolocationEnabled(true), we configure the WebView by passing it two kinds of “clients”: a chrome client, which handles UI, or “chrome”, events (no relation to the browser bearing that name) for your WebView, and a basic client, which handles content-related events such as errors and form resubmission.

First, let’s look at the WebViewClient as implemented in the inner class GeoWebViewClient. It’s not strictly necessary for geolocation, but does something that almost all WebView apps do, which is to load any new URLs (such as when the user touches a hyperlink) in the same WebView. The default behavior is to fire an Intent to load in another browser, which is rarely what you want.

Next, a WebChromeClient as implemented in GeoWebChromeClient is essential for geolocation to work in the WebView. Whenever the WebView encounters Javascript using the Geolocation API, the WebView calls the method onGeolocationPermissionsShowPrompt() in its associated WebChromeClient. The name of the method is slightly misleading in this context, as neither the WebView nor the WebChromeClient actually shows a prompt. If you want to show a prompt, this is the place to do it, and you can find an example in the AOSP source code for packages/apps/Browser/src/com/android/browser/Tab.java. Fortunately, since the app itself declares the ACCESS_FINE_LOCATION permission, the user has effectively already granted permission, and you can simply invoke the callback with the second argument (allow) == true.

The final touch on our app is to wire up the phone’s back button in the onBackPressed() method. If we can go back in the WebView, we do that; otherwise, we back out of the app altogether.

Thanks to Roman Nurik and several others on StackOverflow for your helpful past answers on this topic.

Advertisements

23 Responses to “Enable Geolocation in a WebView (Android)”

  1. Thanks for the good work, eventually a proper code which is working! 😀

  2. I was basically exploring for techniques for my website and observed your blog, “Enable Geolocation in a WebView (Android)
    TurboManage”, would you care in case I personally work with some of your ideas?
    Thx ,Curt

    • That’s fine, Curt. Everything I publish on my blog is for the benefit of the developer community. If you find it helpful, I always appreciate a mention.

      On Wed, Jan 23, 2013 at 11:58 PM, TurboManage

  3. ElGranj said

    Thanks a lot!

    It really help me on my project. This is *exactly* what I needed.

    Cheers!

  4. […] I used this toturial to get the geolocation in the webview : https://turbomanage.wordpress.com/2012/04/23/how-to-enable-geolocation-in-a-webview-android/ […]

  5. vapits said

    Hi there! Great article!
    Is it possible to have some more help?
    I have no errors but it doen’t request any location from my mobile.
    My web app works perfectly on browser (even in android native or chrome browser), in desktops and ios. But in this app it doen’t and i have try almost unlimited solutions 😛

    I would love to have some help on this 🙂

  6. daniel said

    thanks man a lot, was searching for this for hours, code works fine! thanks again, keep up the good work! Cheers

  7. Samuel Santos said

    Hi, Im using XT920 (Motorola) to make my tests and this is not working. I don’t get the prompt to turn GPS on. And ideas why?

  8. jonathan said

    thanks a lot
    worked like a charm 🙂

  9. Geoff said

    YES! I was struggling with this for a few hours- Your solution works perfectly. Thanks!!!

  10. KP said

    David,

    Great tutorial. However, is there a way to get the location if the Android device has no WiFi/GPS or cellular connection. Case in point – when it gets connection through wired ethernet. I’ve an Android hardware with Ethernet only, and can’t find any way to determine it’s location. Either from Android LocationManager, or in WebView, navigator.geolocation.

    Thanks,

  11. […] I follow this post to write this simple app. https://turbomanage.wordpress.com/2012/04/23/how-to-enable-geolocation-in-a-webview-android/ […]

  12. I love your work you have solved my problem thanx.

  13. PK said

    thank you a lot
    you save my life
    ^__________^

  14. Vedeta said

    Works perfect for me!

  15. thanks a lot
    worked like a Charm:)

  16. robie robas said

    thank you so much sir! you’re a genius the code works fine! hooray!! ^_^

  17. Hi! This seems exactly what i need to fix this in my webappview app but with so many attempts im still not getting it to work.
    I have a website http://www.eaqui.pt and on the second text box i have “Location” and a symbol to retrieve it, but through the web app it doesn’t work even with your code. Can you help somehow?

  18. Great post!, Thanks from Colombia!

  19. Robert said

    Thank you for the great work.

    With Android M (6.0) for Geolocation the requesting of Permissions must done at Run Time. Can you make the program work on API 23 and above? That would be great.

    Many thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: