Search code examples
androidgeolocationwebview

Android WebView using GeolocationPermissions


I’ve looked at the various questions regarding this problem on here such as:

But I’m still a bit confused, I know that I am supposed to create my own class from the abstract class WebChromeClient. Which gets the location, but how exactly from there does this object send the webView the geolocation/how do they communicate?

Here is my code: (is this at least on the right track?)

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.webkit.GeolocationPermissions.Callback;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.GeolocationPermissions;

public class site extends Activity {
WebView engine;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);


    WebViewClient yourWebClient = new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.contains("tel:") == true) { 
                Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url)); 
                startActivity(intent); 
            }
            else if(url.contains("visitchicagosouthland") == true) {
                view.loadUrl(url);
            }

//Here is where I create my object, I did this because I only need the location when this
//page is loaded. Could this be part of the problem?

            else if(url.contains("directions.cfm") == true) {
                GeoClient geo = new GeoClient();
                engine.setWebChromeClient(geo);        
                String origin = ""; //how to get origin in correct format?
                Callback call = null;
                geo.onGeolocationPermissionsShowPrompt(origin, call );  
            }
            else {
                /*Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("url")); 
                startActivity(browserIntent);*/
            }
        return true;
        }
    };


    engine = (WebView) findViewById(R.id.web_engine);
    engine.getSettings().setJavaScriptEnabled(true);
    engine.getSettings().setBuiltInZoomControls(true);
    engine.getSettings().setSupportZoom(true); 
    engine.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
    engine.getSettings().setGeolocationEnabled(true);
    engine.setWebViewClient(yourWebClient);
    engine.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
    engine.loadUrl("http://www.visitchicagosouthland.com/jrudnydev/phone/");
}



@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.home, menu);
    return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((keyCode == KeyEvent.KEYCODE_BACK) && engine.canGoBack()) {
        engine.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    if(item.getItemId() == R.id.home) {
        engine.loadUrl("http://www.visitchicagosouthland.com/mobile/");
        return true;
    }
    else if(item.getItemId() == R.id.refresh) {
            engine.reload();
            return true;
    }
    else if(item.getItemId() == R.id.stop) {
            engine.stopLoading();
            return true;
    }
    else {
        return super.onOptionsItemSelected(item);
    }
}

}

final class GeoClient extends WebChromeClient {

  @Override
    public void onProgressChanged(WebView view, int progress) {
        // Activities and WebViews measure progress with different scales.
        // The progress meter will automatically disappear when we reach 100%
        //Activity.setProgress(progress * 100);
    }

@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    //Log.d(LOG_TAG, message);
    // This shows the dialog box.  This can be commented out for dev
    AlertDialog.Builder alertBldr = new AlertDialog.Builder(null);
    alertBldr.setMessage(message);
    alertBldr.setTitle("Alert");
    alertBldr.show();
    result.confirm();
    return true;
}

@Override
public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
// TODO Auto-generated method stub
super.onGeolocationPermissionsShowPrompt(origin, callback);
callback.invoke(origin, true, false);
}

}

my android-manifest.xml:

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

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_GPS" />
<uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
<uses-permission android:name="android.permission.ACCESS_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".site"
              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>
<uses-sdk android:minSdkVersion="4" />

</manifest> 

Solution

  • It is rather simple when the html is your own. There are a couple of ways, I will give you 2 of them.

    Simple way using GET

    Idea is to send the location in the URL (you might need some encoding but as long as it's only numbers and no spaces you are fine

    Some editing for your shouldOverridUrlLoading

    public boolean shouldOverrideUrlLoading(WebView view, String url){
        if (url.needs_geo) //meaning if this is the url that needs the geo location
            url += "?geo=" + your_location;
        view.loadUrl(url);
        return true;
    }
    

    In your JavaScript:

    function getParam(name)
    {
      name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
      var regexS = "[\\?&]"+name+"=([^&#]*)";
      var regex = new RegExp( regexS );
      var results = regex.exec( window.location.href );
      if( results == null )
        return "";
      else
        return results[1];
    }
    

    then

    var geo_location = getParam('geo');
    

    Using WebView.addJavascriptInterface

    (I have never tried to pass values from Java to JavaScript but will probably work as well). The idea is to provide for your JavaScript a Java class that can be accessed to get the parameters you want to pass to JavaScript.

    Inside your Activity class:

    public String location; //as an example
    
        public class SherifJS {
            public String getLocation(){
                return location;
            }
        }
    //bla bla
    
        SherifJS loc = new SherifJS();
        yourWebView.addJavascriptInterface(loc, "locationProvider"); 
    

    Inside your JavaScript:

    <script type="text/javascript">
            <!--
    
    function sherifJS() {
        document.getElementById("locationHolder").innerHTML =
        window.locationProvider.getLocation();
    }
    
            -->
    </script>