javaandroidwebviewandroid-webviewgoogle-chrome-webview

WebChromeClient doesn't ask for location permission anymore


I have an Android App which uses WebView to show a map on Open Street Map and few weeks stop working properly.

A few weeks ago when the user tap on show my location on the web page Android shows a prompt to allow the app to load the current position but at the moment just an error is shown: Geolocation error: user denied Geolocation.

I looked here on SO and on Google to find if some part of my code became deprecated or blocked but I didn't find anything useful. The only information I found was about ActionBarActivity but also using AppCompatActivity the problem was the same.

The MVP version of the MainActivity is the following (I deleted other unuseful lines for this example):

package com.vinaysomawat.careerhigh;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import android.webkit.GeolocationPermissions;
import android.webkit.WebChromeClient;


public class MainActivity extends ActionBarActivity {
    public String mGeolocationOrigin;
    public GeolocationPermissions.Callback mGeolocationCallback;
    private static final int REQUEST_FINE_LOCATION=0;

    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;
        }
    }

    public class GeoWebChromeClient extends WebChromeClient {
        @Override
        public void onGeolocationPermissionsShowPrompt(String origin,
                                                       GeolocationPermissions.Callback callback) {
            String perm = Manifest.permission.ACCESS_FINE_LOCATION;
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
                    ContextCompat.checkSelfPermission(MainActivity.this, perm) == PackageManager.PERMISSION_GRANTED) {
                // we're on SDK < 23 OR user has already granted permission
                callback.invoke(origin, true, false);
            } else {
                if (!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, perm)) {
                    // ask the user for permission
                    ActivityCompat.requestPermissions(MainActivity.this, new String[] {perm}, REQUEST_FINE_LOCATION);

                    // we will use these when user responds
                    mGeolocationOrigin = origin;
                    mGeolocationCallback = callback;
                }
            }}

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_FINE_LOCATION:
                boolean allow = false;
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // user has allowed this permission
                    allow = true;
                }
                if (mGeolocationCallback != null) {
                    // call back to web chrome client
                    mGeolocationCallback.invoke(mGeolocationOrigin, allow, false);
                }
                break;
        }
    }

    WebView mywebview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //Hide TopBar
        getSupportActionBar().hide();

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mywebview = (WebView)findViewById(R.id.webView);
        WebSettings webSettings = mywebview.getSettings();

        // Empty Cache
        mywebview.clearCache(true);

        // Hide Zoom buttons
        mywebview.getSettings().setDisplayZoomControls(false);

        mywebview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        mywebview.getSettings().setBuiltInZoomControls(true);
        mywebview.setWebViewClient(new GeoWebViewClient());
        // Below required for geolocation
        mywebview.getSettings().setJavaScriptEnabled(true);
        mywebview.getSettings().setGeolocationEnabled(true);
        mywebview.setWebChromeClient(new GeoWebChromeClient());

        mywebview.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture, android.os.Message resultMsg)
            {
                WebView.HitTestResult result = view.getHitTestResult();
                String data = result.getExtra();
                Context context = view.getContext();
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(data));
                context.startActivity(browserIntent);
                return false;
            }
        });

        mywebview.loadUrl("https://mycurrentlocation.net/");
        
    }


    @Override
    public void onBackPressed(){
        if(mywebview.canGoBack()) {
            mywebview.goBack();
        } else
        {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item){
        int id = item.getItemId();

        if(id == R.id.action_settings){
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

}

When I click the button to show my current position, in Android Studio I get the following log:

E/Resource: printErrorResource, maybe not a error because module has entative access to resource called by =android.content.res.HwResourcesImpl.printErrorResource:2634 android.content.res.ResourcesImpl.openRawResource:444 android.content.res.Resources.openRawResource:1418 android.content.res.Resources.openRawResource:1362 android.support.v4.graphics.TypefaceCompatBaseImpl.createFromResourcesFontFile:304 android.support.v4.graphics.TypefaceCompat.createFromResourcesFontFile:232 I/ResourcesImplEx: The apk asset path = ApkAssets{path=/system/framework/framework-res.apk} The apk asset path = ApkAssets{path=/system/framework/framework-res-hwext.apk} The apk asset path = ApkAssets{path=/preas/oversea/overlay/GmsConfigOverlay.apk} The apk asset path = ApkAssets{path=/preas/oversea/overlay/GmsGsaConfigOverlay.apk} The apk asset path = ApkAssets{path=/preas/oversea/overlay/GoogleExtServicesConfigOverlay.apk} The apk asset path = ApkAssets{path=/preas/oversea/overlay/GoogleModuleMetadataConfigOverlay.apk} The apk asset path = ApkAssets{path=/preas/oversea/overlay/GooglePermissionControllerConfigOverlay.apk} The apk asset path = ApkAssets{path=/hw_product/overlay/frameworkResOverlay.apk} The apk asset path = ApkAssets{path=/odm/overlay/frameworkResOverlay.apk} The apk asset path = ApkAssets{path=/data/app/com.vinaysomawat.careerhigh-3JvsuNOhaJTzUZrEdMaQnA==/base.apk} I/ResourcesImplEx: The apk asset path = ApkAssets{path=/data/app/com.google.android.webview-Lw6x1ElnmD4d1UEVSG95iA==/base.apk} The apk asset path = ApkAssets{path=/data/app/com.google.android.webview-Lw6x1ElnmD4d1UEVSG95iA==/split_config.it.apk} The apk asset path = ApkAssets{path=/data/app/com.google.android.webview-Lw6x1ElnmD4d1UEVSG95iA==/split_weblayer.apk} The apk asset path = ApkAssets{path=/data/app/com.google.android.trichromelibrary_489608833-ndmJcgRaxXQPmZ7r_KqT-w==/base.apk}

and then this log is shown (I think this is the error banner that say that can't load the position):

D/HiTouch_PressGestureDetector: onAttached, package=com.vinaysomawat.careerhigh, windowType=2, mHiTouchRestricted=false D/mali_winsys: EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000


Solution

  • Yes. I had a similar problem. Location permissions for an android webview and geolocation are no longer handled by the webChromeClient. They are now handled in the same way as an Android native app. I used the following as a guide and it worked well.

    https://developer.android.com/training/location/permissions