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.
Frederic (@JdlF007) said
Thanks for the good work, eventually a proper code which is working! 😀
Thomas Koefod (@crytel) said
Did you get this to work? I got multiple errors when trying it out although I admit I really don’t know Java well.
http://tinyurl.com/adriweals37156 said
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
David Chandler said
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
ElGranj said
Thanks a lot!
It really help me on my project. This is *exactly* what I needed.
Cheers!
Android app and website javascript | CopyQuery said
[…] 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/ […]
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 🙂
daniel said
thanks man a lot, was searching for this for hours, code works fine! thanks again, keep up the good work! Cheers
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?
jonathan said
thanks a lot
worked like a charm 🙂
Geoff said
YES! I was struggling with this for a few hours- Your solution works perfectly. Thanks!!!
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,
David Chandler said
There is no way that I know of. That, in fact, tripped me up during my demo last year at I/O, as we were using hardwired Ethernet.
Android WebView: Geolocation fail on Android 4.4.4 | 我爱源码网 said
[…] I follow this post to write this simple app. https://turbomanage.wordpress.com/2012/04/23/how-to-enable-geolocation-in-a-webview-android/ […]
hussainafridi said
I love your work you have solved my problem thanx.
PK said
thank you a lot
you save my life
^__________^
Vedeta said
Works perfect for me!
Naveed Asghar said
thanks a lot
worked like a Charm:)
robie robas said
thank you so much sir! you’re a genius the code works fine! hooray!! ^_^
werkeninholland said
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?
werkeninholland said
Got it to work! Thank you if it wasn’t for your code it couldn’t happen
Carlos Eduardo Casallas Fonseca said
Great post!, Thanks from Colombia!
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
Jeff LeCoat said
Second the request for the above but to work post Android 6.0 where permissions change.
ASIF ULLAH said
amazing. thanks man. its works perfectly.
Robert said
Did you work with Android 6 and above?
Patrick Burke said
My javascript code is : navigator.geolocation.getCurrentPosition( … ) , but when I implement the WebView solution I get a Location_Unavailable code when I debug against my Samsung (which is using LTE so I should have location) Any ideas?
Nicola D said
Hi David, I followed your guide. How can I use the coordinates found by the webview?
Marthin Alfreinsco Salakory said
Thanks, suport in my webview