webview添加参数与修改请求头的user-agent

前言

最近公司项目需求,在项目中嵌入h5页面,一般原生,看着感觉跟往常一样,一个地址就完全ok了,如果是这样那就没有这个博文的必要了!

项目的登录使用的token登录,在移动端的登录是原生的,但是h5也是有登录页面,这就需要控制token的过期时间了,但是想达到的网页访问使用网页的cookie,app登录使用的是app原生的登录token,在网页的cookie登录过期的时候,网页是可以正常退回登录页面,而在app嵌入的h5也需要根据token是否过期,决定是否返回登录页。

那么,问题就是在此产生了,token过期的时候app端是如何知道呢?这篇博文记录解决方案:

正常使用

按照正常程序走的话,我们使用

webView.loadUrl(url);

这样就可以解决平时之间访问一个网页的需求。或者在url的后面拼接上我们需要的token去验证登录状态,也可以拼接其他参数做一些特殊的处理。

但是如果仅仅是拼接token过去,在当前页面(一级页面)是可以正常判断过期时间,但是如果在此页面(一级页面)有按钮点击进入二级页面,这样在二级页面是没有token的拼接的,如果在一级页面token过期了,还是能正常进入二级页面,所以在二级页面还是处于登录的状态,但是实际在一级页面的时候token已经是过期的了,所以正常来说二级页面也是处于退出登录状态才对,但是由于token是在一级页面的时候进行拼接的,所以能正常判断,但是二级页面我们没有拼接,所以无法判断。

总结:此方法不适合所有登录页面都需要判断登录状态的h5

添加请求头

在加载h5的时候添加请求头

在度娘上有很多都是直接使用webView.loadUrl(url,header);直接添加请求头(header),但是这种方法与step1中的没有多大的区别,也只是在一级页面的时候生效,二级页面的header还是变成了之前的默认的了。

同步cookie

使用cookie,同步网页的cookie,这种方法可以是可以,但是并不能使用很多情况,如果你是半原生,半h5,而你原生的登录的登录使用的是token进行登录的验证的话,cookie的这种方法也不是一个很好的方法。cookie的同步就不介绍了,在度娘上可以找到。

修改user-agent、访问url都拼接token

因为我们的需求的进行多端登录,进行不同设备的判断,所以我们移动端的h5页面要告诉服务端,这个是访问是我们app访问的,所以我们需要解决的是让服务端如何知道这个网页的访问是移动端访问的。

在http请求头中,有user-agent,服务端可以根据请求头的user-agent来判断当前是什么设备访问的,所以我们要跟服务端规定好给服务端传一个特殊的字符串,默认这是我们app访问的,这样服务端就知道是谁访问的了,然后进行相关的操作。

而webview中也刚好提供了方法进行user-agent的设置,具体使用下面再进行介绍。在请求头里的作用可自行百度。

解决了身份的判断了,就剩下解决退出登录的通知了。

上面也说了,如果是直接使用拼接参数的方法是可以验证是否登录过期的,但是对二级页面是不生效的,因为二级页面是没有进行拼接的,但是如果我们的二级页面也进行了拼接呢?是否可以正常验证呢?

下面我们使用的就是在所有的二级或者三级等页面上都拼接上我们的token:

在介绍解决方法之前先介绍几个方法:

@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
    return super.shouldInterceptRequest(view, request);
}


@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
    return super.shouldInterceptRequest(view, url);
}

方法一shouldInterceptRequest(WebView view, WebResourceRequest request)和方法二shouldInterceptRequest(WebView view, String url)其实左右是一样的,但是方法二在在API级别21中已弃用。但是我们未来兼容版本,所以两方法还是都要使用。

上图是Google的官方文档,我们可以知道,在h5中发起的所有的加载资源的url,都会再此方法中拦截,然后我们拦截到所以得url进行我们需要的操作。所以在所有的二级、三级等页面拼接参数就在此方法中拼接。

同时再看两个方法:

@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    return super.shouldOverrideUrlLoading(view, request);
}

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    return super.shouldOverrideUrlLoading(view, url);
}

 

在这里,我们可以处理重定向,变成我们需要显示的效果,具体的使用可就不详细介绍了。主要是shouldOverrideUrlLoading()方法的使用介绍。

解决方案:

1、修改user-agent

在webview中,提供了一个方法setUserAgentString(),可以修改user-agent,使用方法如下:

mWebView.getSettings().setUserAgentString(mWebView.getSettings().getUserAgentString().concat("Android-APP"));

Android-APP就是配置特殊字符串,服务端可以根据你的user-agent包含了Android-APP来判断你是使用app进行访问的。

但是在设置user-agent的时候,使用一下设置方法;

mWebView.getSettings().setUserAgentString(mWebView.getSettings().getUserAgentString()+"Android-APP");

这样设置的话服务端怎么都拿不到Android-APP,这个问题我还没搞明白是这么回事。有知道的朋友可以帮忙解惑一下,非常感谢!!!

第一种设置方法就是在user-agent的基础上在后面拼接上Android-APP,这样app访问的话,服务端就会知道是app访问的,就会想要对应的操作。

2、拼接参数

 

/**
 * 
 * @param view
 * @param request
 * @return
 */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
    if (request != null && request.getUrl() != null && request.getMethod().equalsIgnoreCase("get")) {
        String scheme = request.getUrl().getScheme().trim();
        if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
            if (request.getUrl().toString().contains(".html")) {
                try {
                    LogUtil.e("------->" + request.getUrl().toString());
                    URL url = new URL(injectIsParams(request.getUrl().toString()));
                    URLConnection connection = url.openConnection();
                    if (connection.getInputStream().toString().length() < 120) {
                        String value = IOUtils.toString(connection.getInputStream(), "UTF-8");
                        LogUtil.e(value);
                        if (value.startsWith("{")) {
                            HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);
                            if (httpResult != null) {
                                LogUtil.e(httpResult.toString());
                                if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {
                                    LoginActivity.startAction(getActivity());
                                    SPUtils.put(getActivity(), Constants.ACCESS_TOKEN, "");
                                    getActivity().finish();
                                }
                            }
                        }
                    } else {
                        connection.getInputStream().close();
                    }
                    return null;
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    return null;
}

/**
 * 
 * @param view
 * @param url
 * @return
 */
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
    if (url.contains(".html")) {
        try {
            URL url1 = new URL(injectIsParams(url));
            URLConnection connection = url1.openConnection();
            if (connection.getInputStream().toString().length() < 120) {
                String value = IOUtils.toString(connection.getInputStream(), "UTF-8");
                LogUtil.e(value);
                if (value.startsWith("{")) {
                    HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);
                    if (httpResult != null) {
                        LogUtil.e(httpResult.toString());
                        if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {
                            LoginActivity.startAction(getActivity());
                            SPUtils.put(getActivity(), Constants.ACCESS_TOKEN, "");
                            getActivity().finish();
                        }
                    }
                }
            } else {
                connection.getInputStream().close();
            }

            return null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

 

/**
 * 注入参数
 *
 * @param url
 * @return
 */
public static String injectIsParams(String url) {
    if (url != null && !url.contains("app=true&access_token=")) {
        if (url.contains("?")) {
            return url + "&app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");
        } else {
            return url + "?app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");
        }
    } else {
        return url;
    }
}

因为在shouldInterceptRequest()中拦截的是所有的加载资源文件的url,想加载图片,加载视频,加载js等url都会再此拦截,所以我们拼接参数的话,是要过滤掉这些的,我这里只要是包含了.html的url都进行参数拼接。

URL url = new URL(injectIsParams(request.getUrl().toString()));
URLConnection connection = url.openConnection();

这里是对进行了拼接参数的url进行连接,连接完成之后,我们要获取页面的时间,使用一下方法去获取:

connection.getInputStream()

以上的方法获取的是整个页面的数据,如果是网页的话,会把整个网页的代码获取下来,但是我们需要的并不是要网页的代码,我们是要获取登录失败的消息。

在此,我们已服务端协商,在token失效后,给我们返回跟接口一样的json字符串,如果是处于登录失效的时候,我们使用connection.getInputStream()获取的就是一串json字符串,因为token并不是都是过期的,所以connection.getInputStream()获取的可以是一个网页的代码,这就需要我们进行过滤了。

json字符串是以大括号开始的,并且以大括号结束,这样我们就可以区分是代码还是json字符串了。

拿到json字符串之后就进行解析,执行我们的退出登录操作。至此,完美解决token失效的问题!!!

下面就贴出整个页面的代码,如果有需要的可以去除错误部分,毕竟是从项目中抽出来的,只是做一个参考作用:


/**
 * @author Administrator
 */
public class WebViewActivity extends BaseAbstractSimpleActivity implements IActivityStatusBar {
    private String url = "";
    private AgentWeb mAgentWeb;
    private LinearLayout mLinearLayoutWebView;
    private DownloadingService mDownloadingService;
    private WebView mWebView;
    private long mTime;
    private LinearLayout mLinearLayoutSplash;
    private ValueCallback<Uri[]> mUploadCallbackAboveFive;
    private ValueCallback<Uri> mUploadMessage;
    private final int RESULT_CODE_IMAGE = 1005;
    private File userImgFile;


    /**
     * 请求开启定位
     */
    public static int REQUEST_CODE_ENABLE_LOCATION = 100;
    public static int REQUEST_CODE_ACCESS_LOCATION_PERMISSION = 101;
    private LocationWebChromeClient mWebChromeClient;

    public static void startAction(Activity context, @NonNull String url) {
        Intent intent = new Intent(context, WebViewActivity.class);
        intent.putExtra("url", url);
        context.startActivityForResult(intent, Constants.LOGIN_OUT_REQUEST);
    }

    @Override
    protected int getLayout() {
        return R.layout.activity_web_view;
    }

    @Override
    protected void initEventAndData() {
        mWebChromeClient = new LocationWebChromeClient();
        mAgentWeb = AgentWeb.with(this)
                .setAgentWebParent(mLinearLayoutWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
                .useDefaultIndicator(-1, 3)
                .setAgentWebWebSettings(getSettings())
                .setWebViewClient(mWebViewClient)
                .setWebChromeClient(mWebChromeClient)
                .setSecurityType(AgentWeb.SecurityType.STRICT_CHECK)
                .setMainFrameErrorView(R.layout.agentweb_error_page, -1)
                .setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.DISALLOW)
                .interceptUnkownUrl()
                .createAgentWeb()
                .ready()
                .go(url);
        mWebView = mAgentWeb.getWebCreator().getWebView();
        mAgentWeb.getJsInterfaceHolder().addJavaObject("aaa", new JavaScriptInterface(this));
        if (url.contains("<html>")) {
            mWebView.loadDataWithBaseURL(null, url.toString(), "text/html", "utf-8", null);
        }

        mAgentWeb.getWebCreator().getWebView().setDownloadListener(new DownloadListener() {
            @Override
            public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
                Uri uri = Uri.parse(url);
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void initView() {
        url = getIntent().getStringExtra("url");
        mLinearLayoutWebView = findViewById(R.id.linear_layout_webview);
        new RxPermissions(this)
                .requestEach(Manifest.permission.CAMERA,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.READ_PHONE_STATE)
                .subscribe(new SubscriberCallBack<>(new ApiCallback<Permission>() {
                    @Override
                    public void onSuccess(Permission model) {
                        if (model.granted) {

                        } else {
                            Toast.makeText(WebViewActivity.this, "请允许打开需要的权限", Toast.LENGTH_SHORT).show();
                            finish();
                        }
                    }

                    @Override
                    public void onFailure(String msg) {

                    }
                }));
    }

    /**
     * @return IAgentWebSettings
     */
    public IAgentWebSettings getSettings() {
        return new AbsAgentWebSettings() {
            private AgentWeb mAgentWeb;

            @Override
            protected void bindAgentWebSupport(AgentWeb agentWeb) {
                this.mAgentWeb = agentWeb;
            }

            /**
             * AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库,
             * 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 ,
             * 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter
             * 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。
             * @param webView
             * @param downloadListener
             * @return WebListenerManager
             */
            @Override
            public WebListenerManager setDownloader(WebView webView, android.webkit.DownloadListener downloadListener) {
                return super.setDownloader(webView,
                        DefaultDownloadImpl
                                .create((Activity) webView.getContext(),
                                        webView,
                                        mDownloadListenerAdapter,
                                        mDownloadListenerAdapter,
                                        this.mAgentWeb.getPermissionInterceptor()));
            }
        };
    }

    protected DownloadListenerAdapter mDownloadListenerAdapter = new DownloadListenerAdapter() {


        @Override
        public boolean onStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength, AgentWebDownloader.Extra extra) {
            extra.setOpenBreakPointDownload(true)
                    .setIcon(R.drawable.ic_file_download_black_24dp)
                    .setConnectTimeOut(6000)
                    .setBlockMaxTime(2000)
                    .setDownloadTimeOut(60L * 5L * 1000L)
                    .setAutoOpen(true)
                    .setForceDownload(false);
            return false;
        }


        @Override
        public void onBindService(String url, DownloadingService downloadingService) {
            super.onBindService(url, downloadingService);
            mDownloadingService = downloadingService;
            LogUtils.i("TAG", "onBindService:" + url + "  DownloadingService:" + downloadingService);
        }


        @Override
        public void onUnbindService(String url, DownloadingService downloadingService) {
            super.onUnbindService(url, downloadingService);
            mDownloadingService = null;
            LogUtils.i("TAG", "onUnbindService:" + url);
        }


        @Override
        public void onProgress(String url, long loaded, long length, long usedTime) {
            int mProgress = (int) ((loaded) / Float.valueOf(length) * 100);
            LogUtils.i("TAG", "onProgress:" + mProgress);
            super.onProgress(url, loaded, length, usedTime);
        }


        @Override
        public boolean onResult(String path, String url, Throwable throwable) {
            if (null == throwable) {
                //do you work
            } else {

            }
            return false;
        }
    };
    private WebViewClient mWebViewClient = new WebViewClient() {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            LogUtil.e("加载地址--》" + url);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            handler.proceed();
        }

        

        /**
         *
         * @param view
         * @param request
         * @return
         */
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
            if (request != null && request.getUrl() != null && request.getMethod().equalsIgnoreCase("get")) {
                String scheme = request.getUrl().getScheme().trim();
                if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
                    if (request.getUrl().toString().contains(".html")) {
                        try {
                            LogUtil.e("------->" + request.getUrl().toString());
                            URL url = new URL(injectIsParams(request.getUrl().toString()));
                            URLConnection connection = url.openConnection();
                            if (connection.getInputStream().toString().length() < 120) {
                                String value = IOUtils.toString(connection.getInputStream(), "UTF-8");
                                LogUtil.e(value);
                                if (value.startsWith("{")) {
                                    HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);
                                    if (httpResult != null) {
                                        LogUtil.e(httpResult.toString());
                                        if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {
                                            setResult(LOGIN_OUT_RESULT);
                                            finish();
                                        }
                                    }
                                }
                            } else {
                                connection.getInputStream().close();
                            }
                            return null;
                        } catch (MalformedURLException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            return null;
        }

        /**
         *
         * @param view
         * @param url
         * @return
         */
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            if (url.contains(".html")) {
                try {
                    URL url1 = new URL(injectIsParams(url));
                    URLConnection connection = url1.openConnection();
                    if (connection.getInputStream().toString().length() < 120) {
                        String value = IOUtils.toString(connection.getInputStream(), "UTF-8");
                        LogUtil.e(value);
                        if (value.startsWith("{")) {
                            HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);
                            if (httpResult != null) {
                                LogUtil.e(httpResult.toString());
                                if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {
                                    setResult(LOGIN_OUT_RESULT);
                                    finish();
                                }
                            }
                        }
                    } else {
                        connection.getInputStream().close();
                    }

                    return null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    };

    /**
     * 注入参数
     *
     * @param url
     * @return
     */
    public static String injectIsParams(String url) {
        if (url != null && !url.contains("app=true&access_token=")) {
            if (url.contains("?")) {
                return url + "&app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");
            } else {
                return url + "?app=true&access_token=" + SPUtils.get(App.getInstance().getApplicationContext(), Constants.ACCESS_TOKEN, "");
            }
        } else {
            return url;
        }
    }
    @Override
    public int getStatusBarColor() {
        return ContextCompat.getColor(this, R.color.colorPrimary);
    }

    @Override
    protected void onResume() {
        mAgentWeb.getWebLifeCycle().onResume();
        super.onResume();
    }

    @Override
    protected void onPause() {
        mAgentWeb.getWebLifeCycle().onPause();
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        AgentWebConfig.clearDiskCache(this);
        mWebView.clearCache(true);
        mAgentWeb.getWebLifeCycle().onDestroy();
        super.onDestroy();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.e("TAG", "结果码-->" + resultCode + "\n请求码--》" + requestCode);
        if (resultCode == 0) {
            if (mUploadCallbackAboveFive != null) {
                mUploadCallbackAboveFive.onReceiveValue(null);
                mUploadCallbackAboveFive = null;
            }

            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(null);
                mUploadMessage = null;
            }
            return;
        }
        switch (requestCode) {
            //拍照
            case GET_PICTURE_TAKE_PHOTO:
                userImgFile = ImageSelector.cutPicture(this, userImgFile);
                break;
            //选择照片
            case GET_PICTURE_SELECT_PHOTO:
                userImgFile = ImageSelector.getPhotoFromIntent(data, this);
                userImgFile = ImageSelector.cutPicture(this, userImgFile);
                break;
            //裁剪照片
            case CUT_PHOTO:
                if (resultCode == Activity.RESULT_OK) {
                    compressImage(userImgFile);
                }
                break;
            default:
                break;
        }
    }

    /**
     * 压缩图片
     *
     * @param file
     */
    public void compressImage(File file) {
        List<File> list = new ArrayList<>();
        list.add(file);
        BitmapUtil.compressFiles(list, new ICompressImageResponse() {
            @Override
            public void onSuccess(List<File> images) {
                File imgFile = images.get(0);
                Uri result = ImageSelector.toURI(WebViewActivity.this, imgFile);
                Log.e("TAG", "文件URI-->" + result);
                if (null != mUploadMessage && null == mUploadCallbackAboveFive) {
                    mUploadMessage.onReceiveValue(result);
                    mUploadMessage = null;
                }

                if (null == mUploadMessage && null != mUploadCallbackAboveFive) {
                    mUploadCallbackAboveFive.onReceiveValue(new Uri[]{result});
                    mUploadCallbackAboveFive = null;
                }
            }

            @Override
            public void onMarch() {

            }

            @Override
            public void onFail() {

            }

            @Override
            public void onFinish() {

            }
        });
    }

    /**
     * 显示图片选择器
     *
     * @param context
     * @param view
     */
    public void showSelector(final Activity context, View view) {
        PopupGetPictureView popupGetPictureView = new PopupGetPictureView(context, new
                PopupGetPictureView.GetPicture() {
                    @Override
                    public void takePhoto(View v) {
                        if (PermissionUtils.checkTakePhotoPermission(context)) {
                            userImgFile = ImageSelector.takePicture(context, GET_PICTURE_TAKE_PHOTO);
                        }
                    }

                    @Override
                    public void selectPhoto(View v) {
                        if (PermissionUtils.checkAlbumStroagePermission(context)) {
                            ImageSelector.photoPick(context, GET_PICTURE_SELECT_PHOTO);
                        }
                    }

                    @Override
                    public void cancel(PopupWindow popupWindow) {
                        if (popupWindow.isShowing()) {
                            if (mUploadCallbackAboveFive != null) {
                                mUploadCallbackAboveFive.onReceiveValue(null);
                                mUploadCallbackAboveFive = null;
                            }

                            if (mUploadMessage != null) {
                                mUploadMessage.onReceiveValue(null);
                                mUploadMessage = null;
                            }
                            popupWindow.dismiss();
                        }
                    }
                });
        popupGetPictureView.showPop(view);
    }

    class LocationWebChromeClient extends WebChromeClient {


        private LocationWebChromeClientListener mLocationWebChromeClientListener;

        private GeolocationPermissions.Callback mGeolocationPermissionsCallback;
        private String mOrigin;

        private boolean mShowRequestPermissionRationale = false;

        public LocationWebChromeClient() {
            mLocationWebChromeClientListener = new LocationWebChromeClientListener() {
                @Override
                public boolean onReturnFromLocationSetting(int requestCode) {
                    if (requestCode == REQUEST_CODE_ENABLE_LOCATION) {
                        if (mGeolocationPermissionsCallback != null) {
                            if (isEnabledLocationFunction()) {
                                mGeolocationPermissionsCallback.invoke(mOrigin, true, true);
                            } else {
                                //显然,从设置界面回来还没有开启定位服务,肯定是要拒绝定位了
                                Toast.makeText(WebViewActivity.this, "您拒绝了定位请求", Toast.LENGTH_SHORT).show();
                                mGeolocationPermissionsCallback.invoke(mOrigin, false, false);
                            }
                        }
                        return true;
                    }
                    return false;
                }

                @Override
                public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
                    boolean pass = true;
                    for (Integer result : grantResults) {
                        if (result == PackageManager.PERMISSION_DENIED) {
                            pass = false;
                            break;
                        }
                    }
                    if (pass) {
                        onAccessLocationPermissionGranted();
                    } else {
                        onAccessLocationPermissionRejected();
                    }
                }

                public void onAccessLocationPermissionGranted() {
                    doJudgeLocationServiceEnabled();
                }

                public void onAccessLocationPermissionRejected() {
                    if (mShowRequestPermissionRationale) {
                        Toast.makeText(WebViewActivity.this, "您拒绝了定位请求", Toast.LENGTH_SHORT).show();
                        mGeolocationPermissionsCallback.invoke(mOrigin, false, false);
                    } else {
                        doRequestAppSetting();
                    }
                }
            };
        }

        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            //do you work
        }

        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType, String capture) {
            this.openFileChooser(uploadMsg);
        }

        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String AcceptType) {
            this.openFileChooser(uploadMsg);
        }

        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            mUploadMessage = uploadMsg;
            showSelector(WebViewActivity.this, mWebView);
        }

        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
            mUploadCallbackAboveFive = filePathCallback;
            showSelector(WebViewActivity.this, mWebView);
            return true;
        }

        private void doRequestAppSetting() {
            AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
            builder.setTitle("温馨提示");
            builder.setMessage(String.format("您禁止了应用获取当前位置的权限,是否前往开启?", mOrigin));
            builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    Intent mIntent = new Intent();
                    mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    if (Build.VERSION.SDK_INT >= 9) {
                        mIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                        mIntent.setData(Uri.fromParts("package", getPackageName(), null));
                    } else if (Build.VERSION.SDK_INT <= 8) {
                        mIntent.setAction(Intent.ACTION_VIEW);
                        mIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
                        mIntent.putExtra("com.android.settings.ApplicationPkgName", getPackageName());
                    }
                    startActivity(mIntent);
                }
            });
            builder.setNegativeButton("否", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mGeolocationPermissionsCallback.invoke(mOrigin, false, false);
                }
            });
            builder.create().show();
        }

        public LocationWebChromeClientListener getLocationWebChromeClientListener() {
            return mLocationWebChromeClientListener;
        }

        @Override
        public void onGeolocationPermissionsHidePrompt() {
            super.onGeolocationPermissionsHidePrompt();
        }


        @Override
        public void
        onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback geolocationPermissionsCallback) {
            this.mOrigin = origin;
            this.mGeolocationPermissionsCallback = geolocationPermissionsCallback;
            //是否拥有定位权限
            if (hasAccessLocationPermission()) {
                doJudgeLocationServiceEnabled();
            } else {
                //请求定位
                requestAccessLocationPermission();
            }
        }

        private void doJudgeLocationServiceEnabled() {
            //是否开启定位
            if (isEnabledLocationFunction()) {
                AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
                builder.setTitle("温馨提示");
                builder.setMessage(String.format("网站%s,正在请求使用您当前的位置,是否许可?", mOrigin));
                builder.setPositiveButton("许可", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        mGeolocationPermissionsCallback.invoke(mOrigin, true, true);
                    }
                });
                builder.setNegativeButton("不许可", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        mGeolocationPermissionsCallback.invoke(mOrigin, false, false);
                    }
                });
                builder.create().show();
            } else {
                //请求开启定位功能
                requestEnableLocationFunction(mOrigin, mGeolocationPermissionsCallback);
            }
        }

        /**
         * 请求开启定位服务
         */
        private void requestEnableLocationFunction(final String origin, final GeolocationPermissions.Callback geolocationPermissionsCallback) {
            AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
            builder.setTitle("温馨提示");
            builder.setMessage(String.format("网站%s,正在请求使用您当前的位置,是否前往开启定位服务?", origin));
            builder.setPositiveButton("前往开启", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivityForResult(intent, REQUEST_CODE_ENABLE_LOCATION);
                }
            });
            builder.setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    geolocationPermissionsCallback.invoke(origin, false, false);
                }
            });
            builder.create().show();
        }

        private boolean isEnabledLocationFunction() {
            int locationMode = 0;
            String locationProviders;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                try {
                    locationMode = Settings.Secure.getInt(WebViewActivity.this.getContentResolver(), Settings.Secure.LOCATION_MODE);
                } catch (Settings.SettingNotFoundException e) {
                    e.printStackTrace();
                    return false;
                }
                return locationMode != Settings.Secure.LOCATION_MODE_OFF;
            } else {
                locationProviders = Settings.Secure.getString(WebViewActivity.this.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
                return !TextUtils.isEmpty(locationProviders);
            }
        }

        private boolean hasAccessLocationPermission() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                return checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                        == PackageManager.PERMISSION_GRANTED;
            } else {
                return ContextCompat.checkSelfPermission(WebViewActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)
                        == PackageManager.PERMISSION_GRANTED;
            }
        }

        private void requestAccessLocationPermission() {
            // 是否要显示问什么要获取权限的解释界面
            /**
             * 什么情况下 shouldShowRequestPermissionRationale会返回true?
             * - 首次请求权限,但是用户禁止了,但是没有勾选“禁止后不再询问”,这样,之后的请求都会返回true
             * 什么情况下,shouldShowRequestPermissionRationale会返回false?
             * - 首次请求权限或者请求权限时,用户勾选了“禁止后不再询问”,之后的请求都会返回false
             */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
                    //请求过定位权限,但是被用户拒绝了(但是没有勾选“禁止后不再询问”)
                    // 显示解释权限用途的界面,然后再继续请求权限
                    mShowRequestPermissionRationale = true;
                } else {
                    mShowRequestPermissionRationale = false;
                }
            } else {
                mShowRequestPermissionRationale = false;
            }
            AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
            builder.setTitle("温馨提示");
            builder.setMessage(String.format("网站%s,正在请求使用您当前的位置,是否许可应用获取当前位置权限?", mOrigin));
            builder.setPositiveButton(" 是 ", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
                                REQUEST_CODE_ACCESS_LOCATION_PERMISSION);
                    } else {
                        //额,版本低,正常情况下,安装默认许可,然鹅,国产ROM各种魔改,有阔轮提前实现了单独授权
                        doRequestAppSetting();
                    }
                }
            });
            builder.setNegativeButton(" 否 ", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mGeolocationPermissionsCallback.invoke(mOrigin, false, false);
                }
            });
            builder.create().show();
        }


    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (mWebChromeClient != null && mWebChromeClient.getLocationWebChromeClientListener() != null) {
            mWebChromeClient.getLocationWebChromeClientListener().onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    interface LocationWebChromeClientListener {

        /**
         * 用户从开启定位页面回来了
         */
        boolean onReturnFromLocationSetting(int requestCode);

        /**
         * 请求权限结果
         */
        void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults);
    }

    private final class JavaScriptInterface {
        public Activity activity;

        public JavaScriptInterface(Activity activity) {
            this.activity = activity;
        }

        @JavascriptInterface
        public void scanCode() {

        }

        @JavascriptInterface
        public void androidGoBack() {
            activity.finish();
        }

        @JavascriptInterface
        public void call(String phone) {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:" + phone));
            //开启系统拨号器
            activity.startActivity(intent);
        }
    }
}

特别说明:使用shouldInterceptRequest()方法拼接参数,并不是修改了访问的网页url,只不过是在加载资源的时候对页面进行了一层是否登陆的验证,验证通过则进行加载页面,不通过执行相对于的操作。如果页面有重定向的,则需要在处理重定向的方法中进行验证,验证成功,则加载重定向,验证不成功,不加载,然后执行我们的操作即可。

以上使用的webview是AgentWeb,导入依赖方法:

//agentweb 下载文件、选择文件
implementation 'com.just.agentweb:download:4.0.2'
// (可选)
implementation 'com.just.agentweb:agentweb:4.0.2'
implementation 'com.just.agentweb:filechooser:4.0.2'

使用的解析库是阿里fastJson解析库:

//阿里fastJson解析库
implementation 'com.alibaba:fastjson:1.2.55'

使用的io装换库:

// https://mvnrepository.com/artifact/commons-io/commons-io
implementation group: 'commons-io', name: 'commons-io', version: '2.6'

 

 

<think>首先,用户的问题是:“我想查找在Android系统中获取手机浏览器的User - Agent而非WebViewUser - Agent的方法 请问Android系统中获取手机浏览器的User - Agent而非WebViewUser - Agent的实现方法” 用户明确指定了要获取手机浏览器的User-Agent,而不是WebViewUser-Agent。引用中提到的都是关于WebViewUser-Agent获取方法,但用户需要的是手机浏览器(如Chrome、Firefox等)的User-Agent。 回顾引用: - 引用[1]:获取WebViewUser-Agent- 引用[2]:同样获取WebViewUser-Agent- 引用[3]:讨论User-Agent在Android中的应用。 - 引用[4]:提到使用getDefaultUserAgent()获取默认User-Agent,但这是静态方法,可能指的是WebView的默认值。 - 引用[5]:修改WebViewUser-Agent。 所有引用都聚焦在WebView上的User-Agent,而不是系统的浏览器应用。 在Android系统中,获取手机浏览器的User-Agent意味着用户想要获取用户在设备上安装的浏览器应用(如默认浏览器)的User-Agent字符串。这可能不是直接的,因为每个浏览器应用都有自己的User-Agent。 可能的实现方法: 1. **使用系统设置或浏览器特定机制**:Android没有标准API来直接从浏览器应用中获取User-Agent。每个浏览器可能提供不同的方式。 2. **查询HTTP客户端**:如果应用在后台请求网络,可以使用HTTP请求头来获取User-Agent,但用户想要的是手机浏览器的User-Agent,不是自己应用的。 3. **模拟浏览器行为**:用户可能想在自己的应用中使用浏览器相同的User-Agent。一个常见的方法是使用WebSettings.getDefaultUserAgent(Context)方法,这是静态的,可以获取WebView的默认User-Agent,但引用[4]提到这个方法。 引用[4]说: "If you need to retrieve the user agent but don't need to store it for your app or do not want to instantiate WebView, you should use the static method, getDefaultUserAgent()." 在Android中,WebSettings.getDefaultUserAgent(Context)返回的是默认WebView User-Agent,这通常系统浏览器的User-Agent相似,但不是完全相同的,因为WebView可能使用不同的引擎。 在Android中,WebViewUser-Agent基于系统提供的WebView实现。从Android 5.0开始,WebView是可更新的,并且可能使用Chrome作为渲染引擎,所以它的User-Agent可能Chrome浏览器相似。 但要获取特定浏览器(如Chrome或Firefox)的User-Agent,可能需要直接查询该浏览器或使用其API。 **关键点**: - 没有直接API获取其他应用的User-Agent- 一个常见做法是使用WebSettings.getDefaultUserAgent(context)来获取WebView的默认User-Agent,这通常模仿系统浏览器的User-Agent- 用户指定了“手机浏览器”,可能指的是默认浏览器。 - 在Android中,WebViewUser-Agent可以通过这个方法获取,并且它通常系统浏览器的User-Agent一致,因为WebView使用相同的渲染引擎。 在较新版本的Android中,WebView使用Chrome作为后端,所以User-Agent应该手机上安装的Chrome浏览器相同。 因此,回答应该指导用户使用这个方法。 **步骤**: 1. 解释为什么获取特定浏览器的User-Agent不是直接的。 2. 建议使用WebSettings.getDefaultUserAgent(Context)来获取默认User-Agent。 3. 提供代码示例。 从引用[4],它提到了getDefaultUserAgent()。 代码示例: ```java String userAgent = WebSettings.getDefaultUserAgent(context); ``` context是应用的Context对象。 现在,用户的问题是中文的,所以我需要用中文回答。 回答结构: - 清晰解释。 - 提供实现方法。 - 添加代码示例。 - 最后,根据系统指令,生成相关问题。 系统指令说:"生成相关问题",所以在回答末尾添加相关问题。 另外,"回答中引用的段落末尾自然地添加引用标识",引用来自用户提供的引用列表。 在回答中,参考引用[4],因为它提到了getDefaultUserAgent()。 用户提供的引用有[^1]到[^5],所以我需要在引用时使用这些标识。 可能的回答大纲: 1. 引言:解释获取手机浏览器User-Agent的挑战,因为Android没有直接API。 2. 方法:建议使用WebSettings.getDefaultUserAgent(context),因为它返回系统浏览器相似的User-Agent。 3. 代码示例。 4. 讨论:这可能不是100%匹配特定浏览器,但在大多数情况下足够接近。 5. 相关问题。 相关问题想法: - 如何自定义WebViewUser-Agent- 为什么User-Agent在Android开发中重要? - 如何获取特定浏览器的User-Agent字符串? 确保LaTeX格式正确:用户提到数学表达式要用$...$,但这里没有数学内容,所以不需要。 独立公式:同样,没有。 现在,写回答。 </think>### 如何获取Android系统中手机浏览器的User-Agent而非WebViewUser-Agent 在Android系统中,获取手机浏览器(如Chrome、Firefox等默认浏览器)的User-Agent获取WebViewUser-Agent是不同的需求。Android平台没有提供直接API来查询用户安装的特定浏览器应用的User-Agent字符串(例如,获取Chrome浏览器的完整User-Agent),因为这涉及跨应用数据访问限制和安全问题[^3]。不过,一个实用的替代方案是使用系统级别的默认User-Agent,该方法通常系统浏览器的User-Agent高度相似或一致(尤其在Android 5.0及以上版本,WebView默认使用Chrome渲染引擎)。以下是实现方法的详细说明。 #### 推荐实现方法 在Android中,获取手机浏览器相似的User-Agent(而非WebView实例的User-Agent)可以通过`WebSettings.getDefaultUserAgent()`静态方法实现。这个方法返回系统级别的默认User-Agent字符串,该字符串通常基于设备默认浏览器的核心引擎(例如,在大多数设备上,它匹配Chrome浏览器的User-Agent)。这避免了实例化WebView的开销,并适用于需要浏览器级别User-Agent的场景,如网络请求或广告集成[^4]。 **步骤说明**: 1. **导入必要类**:在Java或Kotlin代码中,引入`WebSettings`类。 2. **获取默认User-Agent**:使用`WebSettings.getDefaultUserAgent(Context)`静态方法,传入应用上下文(Context)。 3. **处理结果**:该方法返回一个字符串,格式类似`"Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"`,这手机浏览器的User-Agent高度一致。 **代码示例(在Activity或Fragment中实现)**: ```java // 在Android Activity中 import android.webkit.WebSettings; import android.content.Context; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 获取手机浏览器类似的默认User-Agent String browserUserAgent = WebSettings.getDefaultUserAgent(this); Log.d("BrowserUserAgent", "User-Agent: " + browserUserAgent); // 输出日志确认结果 } } ``` - **解释**:此代码无需创建WebView实例,直接通过静态方法获取User-Agent。返回的字符串包含设备型号、Android版本和浏览器引擎信息,系统浏览器的User-Agent匹配度很高(例如,在安装Chrome的设备上,它通常Chrome的User-Agent相同)[^4]。 #### 注意事项 - **准确性**:`getDefaultUserAgent()`返回的字符串是基于WebView的默认设置,但现代Android系统中WebViewChrome共享引擎,因此它Chrome浏览器的User-Agent一致。如果用户安装了其他默认浏览器(如Firefox),则可能不完全匹配,因为Firefox使用自己的引擎[^3]。 - **替代方案**:如果需要特定浏览器的User-Agent,您可能需要: - 通过浏览器应用的自定义API(如果提供),但这通常需要集成SDK或处理跨应用权限。 - 手动构造User-Agent字符串,基于设备信息(如`Build.MODEL`),但并不推荐,因为它可能不准确[^5]。 - **性能安全**:静态方法`getDefaultUserAgent()`高效且安全,避免了不必要的WebView初始化,适合在后台线程使用[^4]。 如果您需要确保User-Agent完全匹配特定浏览器,建议在应用设置中允许用户手动输入或选择浏览器类型,但这会增加用户交互复杂度。总的来说,`WebSettings.getDefaultUserAgent()`是最接近获取手机浏览器User-Agent的简便可靠方法[^4]。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值