webview添加參數(shù)與修改請(qǐng)求頭的user-agent實(shí)例
前言
最近公司項(xiàng)目需求,在項(xiàng)目中嵌入h5頁(yè)面,一般原生,看著感覺(jué)跟往常一樣,一個(gè)地址就完全ok了,如果是這樣那就沒(méi)有這個(gè)博文的必要了!
項(xiàng)目的登錄使用的token登錄,在移動(dòng)端的登錄是原生的,但是h5也是有登錄頁(yè)面,這就需要控制token的過(guò)期時(shí)間了,但是想達(dá)到的網(wǎng)頁(yè)訪問(wèn)使用網(wǎng)頁(yè)的cookie,app登錄使用的是app原生的登錄token,在網(wǎng)頁(yè)的cookie登錄過(guò)期的時(shí)候,網(wǎng)頁(yè)是可以正常退回登錄頁(yè)面,而在app嵌入的h5也需要根據(jù)token是否過(guò)期,決定是否返回登錄頁(yè)。
那么,問(wèn)題就是在此產(chǎn)生了,token過(guò)期的時(shí)候app端是如何知道呢?這篇博文記錄解決方案:
正常使用
按照正常程序走的話,我們使用
webView.loadUrl(url);
這樣就可以解決平時(shí)之間訪問(wèn)一個(gè)網(wǎng)頁(yè)的需求?;蛘咴趗rl的后面拼接上我們需要的token去驗(yàn)證登錄狀態(tài),也可以拼接其他參數(shù)做一些特殊的處理。
但是如果僅僅是拼接token過(guò)去,在當(dāng)前頁(yè)面(一級(jí)頁(yè)面)是可以正常判斷過(guò)期時(shí)間,但是如果在此頁(yè)面(一級(jí)頁(yè)面)有按鈕點(diǎn)擊進(jìn)入二級(jí)頁(yè)面,這樣在二級(jí)頁(yè)面是沒(méi)有token的拼接的,如果在一級(jí)頁(yè)面token過(guò)期了,還是能正常進(jìn)入二級(jí)頁(yè)面,所以在二級(jí)頁(yè)面還是處于登錄的狀態(tài),但是實(shí)際在一級(jí)頁(yè)面的時(shí)候token已經(jīng)是過(guò)期的了,所以正常來(lái)說(shuō)二級(jí)頁(yè)面也是處于退出登錄狀態(tài)才對(duì),但是由于token是在一級(jí)頁(yè)面的時(shí)候進(jìn)行拼接的,所以能正常判斷,但是二級(jí)頁(yè)面我們沒(méi)有拼接,所以無(wú)法判斷。
總結(jié):此方法不適合所有登錄頁(yè)面都需要判斷登錄狀態(tài)的h5
添加請(qǐng)求頭
在加載h5的時(shí)候添加請(qǐng)求頭
在度娘上有很多都是直接使用webView.loadUrl(url,header);直接添加請(qǐng)求頭(header),但是這種方法與step1中的沒(méi)有多大的區(qū)別,也只是在一級(jí)頁(yè)面的時(shí)候生效,二級(jí)頁(yè)面的header還是變成了之前的默認(rèn)的了。
同步cookie
使用cookie,同步網(wǎng)頁(yè)的cookie,這種方法可以是可以,但是并不能使用很多情況,如果你是半原生,半h5,而你原生的登錄的登錄使用的是token進(jìn)行登錄的驗(yàn)證的話,cookie的這種方法也不是一個(gè)很好的方法。cookie的同步就不介紹了,在度娘上可以找到。
修改user-agent、訪問(wèn)url都拼接token
因?yàn)槲覀兊男枨蟮倪M(jìn)行多端登錄,進(jìn)行不同設(shè)備的判斷,所以我們移動(dòng)端的h5頁(yè)面要告訴服務(wù)端,這個(gè)是訪問(wèn)是我們app訪問(wèn)的,所以我們需要解決的是讓服務(wù)端如何知道這個(gè)網(wǎng)頁(yè)的訪問(wèn)是移動(dòng)端訪問(wèn)的。
在http請(qǐng)求頭中,有user-agent,服務(wù)端可以根據(jù)請(qǐng)求頭的user-agent來(lái)判斷當(dāng)前是什么設(shè)備訪問(wèn)的,所以我們要跟服務(wù)端規(guī)定好給服務(wù)端傳一個(gè)特殊的字符串,默認(rèn)這是我們app訪問(wèn)的,這樣服務(wù)端就知道是誰(shuí)訪問(wèn)的了,然后進(jìn)行相關(guān)的操作。
而webview中也剛好提供了方法進(jìn)行user-agent的設(shè)置,具體使用下面再進(jìn)行介紹。在請(qǐng)求頭里的作用可自行百度。
解決了身份的判斷了,就剩下解決退出登錄的通知了。
上面也說(shuō)了,如果是直接使用拼接參數(shù)的方法是可以驗(yàn)證是否登錄過(guò)期的,但是對(duì)二級(jí)頁(yè)面是不生效的,因?yàn)槎?jí)頁(yè)面是沒(méi)有進(jìn)行拼接的,但是如果我們的二級(jí)頁(yè)面也進(jìn)行了拼接呢?是否可以正常驗(yàn)證呢?
下面我們使用的就是在所有的二級(jí)或者三級(jí)等頁(yè)面上都拼接上我們的token:
在介紹解決方法之前先介紹幾個(gè)方法:
@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)其實(shí)左右是一樣的,但是方法二在在API級(jí)別21中已棄用。但是我們未來(lái)兼容版本,所以兩方法還是都要使用。


上圖是Google的官方文檔,我們可以知道,在h5中發(fā)起的所有的加載資源的url,都會(huì)再此方法中攔截,然后我們攔截到所以得url進(jìn)行我們需要的操作。所以在所有的二級(jí)、三級(jí)等頁(yè)面拼接參數(shù)就在此方法中拼接。
同時(shí)再看兩個(gè)方法:
@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);
}


在這里,我們可以處理重定向,變成我們需要顯示的效果,具體的使用可就不詳細(xì)介紹了。主要是shouldOverrideUrlLoading()方法的使用介紹。
解決方案:
1、修改user-agent
在webview中,提供了一個(gè)方法setUserAgentString(),可以修改user-agent,使用方法如下:
mWebView.getSettings().setUserAgentString(mWebView.getSettings().getUserAgentString().concat("Android-APP"));
Android-APP就是配置特殊字符串,服務(wù)端可以根據(jù)你的user-agent包含了Android-APP來(lái)判斷你是使用app進(jìn)行訪問(wèn)的。
但是在設(shè)置user-agent的時(shí)候,使用一下設(shè)置方法;
mWebView.getSettings().setUserAgentString(mWebView.getSettings().getUserAgentString()+"Android-APP");
這樣設(shè)置的話服務(wù)端怎么都拿不到Android-APP,這個(gè)問(wèn)題我還沒(méi)搞明白是這么回事。有知道的朋友可以幫忙解惑一下,非常感謝?。?!
第一種設(shè)置方法就是在user-agent的基礎(chǔ)上在后面拼接上Android-APP,這樣app訪問(wèn)的話,服務(wù)端就會(huì)知道是app訪問(wèn)的,就會(huì)想要對(duì)應(yīng)的操作。
2、拼接參數(shù)
/**
*
* @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;
}
/**
* 注入?yún)?shù)
*
* @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;
}
}
因?yàn)樵趕houldInterceptRequest()中攔截的是所有的加載資源文件的url,想加載圖片,加載視頻,加載js等url都會(huì)再此攔截,所以我們拼接參數(shù)的話,是要過(guò)濾掉這些的,我這里只要是包含了.html的url都進(jìn)行參數(shù)拼接。
URL url = new URL(injectIsParams(request.getUrl().toString()));
URLConnection connection = url.openConnection();
這里是對(duì)進(jìn)行了拼接參數(shù)的url進(jìn)行連接,連接完成之后,我們要獲取頁(yè)面的時(shí)間,使用一下方法去獲?。?/p>
connection.getInputStream()
以上的方法獲取的是整個(gè)頁(yè)面的數(shù)據(jù),如果是網(wǎng)頁(yè)的話,會(huì)把整個(gè)網(wǎng)頁(yè)的代碼獲取下來(lái),但是我們需要的并不是要網(wǎng)頁(yè)的代碼,我們是要獲取登錄失敗的消息。
在此,我們已服務(wù)端協(xié)商,在token失效后,給我們返回跟接口一樣的json字符串,如果是處于登錄失效的時(shí)候,我們使用connection.getInputStream()獲取的就是一串json字符串,因?yàn)閠oken并不是都是過(guò)期的,所以connection.getInputStream()獲取的可以是一個(gè)網(wǎng)頁(yè)的代碼,這就需要我們進(jìn)行過(guò)濾了。
json字符串是以大括號(hào)開(kāi)始的,并且以大括號(hào)結(jié)束,這樣我們就可以區(qū)分是代碼還是json字符串了。
拿到j(luò)son字符串之后就進(jìn)行解析,執(zhí)行我們的退出登錄操作。至此,完美解決token失效的問(wèn)題?。。?/p>
下面就貼出整個(gè)頁(yè)面的代碼,如果有需要的可以去除錯(cuò)誤部分,畢竟是從項(xiàng)目中抽出來(lái)的,只是做一個(gè)參考作用:
/**
* @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;
/**
* 請(qǐng)求開(kāi)啟定位
*/
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, "請(qǐng)?jiān)试S打開(kāi)需要的權(quán)限", 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 內(nèi)部刪除了 DownloadListener 監(jiān)聽(tīng) ,以及相關(guān)API ,將 Download 部分完全抽離出來(lái)獨(dú)立一個(gè)庫(kù),
* 如果你需要使用 AgentWeb Download 部分 , 請(qǐng)依賴上 compile 'com.just.agentweb:download:4.0.0 ,
* 如果你需要監(jiān)聽(tīng)下載結(jié)果,請(qǐng)自定義 AgentWebSetting , New 出 DefaultDownloadImpl,傳入DownloadListenerAdapter
* 實(shí)現(xiàn)進(jìn)度或者結(jié)果監(jiān)聽(tīng),例如下面這個(gè)例子,如果你不需要監(jiān)聽(tīng)進(jìn)度,或者下載結(jié)果,下面 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;
}
};
/**
* 注入?yún)?shù)
*
* @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", "結(jié)果碼-->" + resultCode + "\n請(qǐng)求碼--》" + 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 {
//顯然,從設(shè)置界面回來(lái)還沒(méi)有開(kāi)啟定位服務(wù),肯定是要拒絕定位了
Toast.makeText(WebViewActivity.this, "您拒絕了定位請(qǐng)求", 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, "您拒絕了定位請(qǐng)求", 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("您禁止了應(yīng)用獲取當(dāng)前位置的權(quán)限,是否前往開(kāi)啟?", 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;
//是否擁有定位權(quán)限
if (hasAccessLocationPermission()) {
doJudgeLocationServiceEnabled();
} else {
//請(qǐng)求定位
requestAccessLocationPermission();
}
}
private void doJudgeLocationServiceEnabled() {
//是否開(kāi)啟定位
if (isEnabledLocationFunction()) {
AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
builder.setTitle("溫馨提示");
builder.setMessage(String.format("網(wǎng)站%s,正在請(qǐng)求使用您當(dāng)前的位置,是否許可?", 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 {
//請(qǐng)求開(kāi)啟定位功能
requestEnableLocationFunction(mOrigin, mGeolocationPermissionsCallback);
}
}
/**
* 請(qǐng)求開(kāi)啟定位服務(wù)
*/
private void requestEnableLocationFunction(final String origin, final GeolocationPermissions.Callback geolocationPermissionsCallback) {
AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
builder.setTitle("溫馨提示");
builder.setMessage(String.format("網(wǎng)站%s,正在請(qǐng)求使用您當(dāng)前的位置,是否前往開(kāi)啟定位服務(wù)?", origin));
builder.setPositiveButton("前往開(kāi)啟", 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() {
// 是否要顯示問(wèn)什么要獲取權(quán)限的解釋界面
/**
* 什么情況下 shouldShowRequestPermissionRationale會(huì)返回true?
* - 首次請(qǐng)求權(quán)限,但是用戶禁止了,但是沒(méi)有勾選“禁止后不再詢問(wèn)”,這樣,之后的請(qǐng)求都會(huì)返回true
* 什么情況下,shouldShowRequestPermissionRationale會(huì)返回false?
* - 首次請(qǐng)求權(quán)限或者請(qǐng)求權(quán)限時(shí),用戶勾選了“禁止后不再詢問(wèn)”,之后的請(qǐng)求都會(huì)返回false
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
//請(qǐng)求過(guò)定位權(quán)限,但是被用戶拒絕了(但是沒(méi)有勾選“禁止后不再詢問(wèn)”)
// 顯示解釋權(quán)限用途的界面,然后再繼續(xù)請(qǐng)求權(quán)限
mShowRequestPermissionRationale = true;
} else {
mShowRequestPermissionRationale = false;
}
} else {
mShowRequestPermissionRationale = false;
}
AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
builder.setTitle("溫馨提示");
builder.setMessage(String.format("網(wǎng)站%s,正在請(qǐng)求使用您當(dāng)前的位置,是否許可應(yīng)用獲取當(dāng)前位置權(quán)限?", 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 {
//額,版本低,正常情況下,安裝默認(rèn)許可,然鵝,國(guó)產(chǎn)ROM各種魔改,有闊輪提前實(shí)現(xiàn)了單獨(dú)授權(quán)
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 {
/**
* 用戶從開(kāi)啟定位頁(yè)面回來(lái)了
*/
boolean onReturnFromLocationSetting(int requestCode);
/**
* 請(qǐng)求權(quán)限結(jié)果
*/
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));
//開(kāi)啟系統(tǒng)撥號(hào)器
activity.startActivity(intent);
}
}
}
特別說(shuō)明:使用shouldInterceptRequest()方法拼接參數(shù),并不是修改了訪問(wèn)的網(wǎng)頁(yè)url,只不過(guò)是在加載資源的時(shí)候?qū)?yè)面進(jìn)行了一層是否登陸的驗(yàn)證,驗(yàn)證通過(guò)則進(jìn)行加載頁(yè)面,不通過(guò)執(zhí)行相對(duì)于的操作。如果頁(yè)面有重定向的,則需要在處理重定向的方法中進(jìn)行驗(yàn)證,驗(yàn)證成功,則加載重定向,驗(yàn)證不成功,不加載,然后執(zhí)行我們的操作即可。
以上使用的webview是AgentWeb,導(dǎo)入依賴方法:
//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'
使用的解析庫(kù)是阿里fastJson解析庫(kù):
//阿里fastJson解析庫(kù)
implementation 'com.alibaba:fastjson:1.2.55'
使用的io裝換庫(kù):
// https://mvnrepository.com/artifact/commons-io/commons-io
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
以上這篇webview添加參數(shù)與修改請(qǐng)求頭的user-agent實(shí)例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Android中ViewFlipper的使用及設(shè)置動(dòng)畫(huà)效果實(shí)例詳解
這篇文章主要介紹了Android中ViewFlipper的使用及設(shè)置動(dòng)畫(huà)效果的方法,以實(shí)例形式較為詳細(xì)的分析了ViewFlipper的功能、原理及設(shè)置與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android自定義View繪制貝塞爾曲線中小紅點(diǎn)的方法
貝塞爾曲線的本質(zhì)是通過(guò)數(shù)學(xué)計(jì)算的公式來(lái)繪制平滑的曲線,分為一階,二階,三階及多階。但是這里不講數(shù)學(xué)公式和驗(yàn)證,那些偉大的數(shù)學(xué)家已經(jīng)證明過(guò)了,所以就只講講Android開(kāi)發(fā)中的運(yùn)用吧2023-02-02
Android實(shí)現(xiàn)為L(zhǎng)istView同時(shí)設(shè)置點(diǎn)擊時(shí)的背景和點(diǎn)擊松手之后的背景
這篇文章主要介紹了Android實(shí)現(xiàn)為L(zhǎng)istView同時(shí)設(shè)置點(diǎn)擊時(shí)的背景和點(diǎn)擊松手之后的背景,以實(shí)例形式較為詳細(xì)的分析了界面元素與功能的實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02
Android應(yīng)用創(chuàng)建桌面快捷方式代碼
這篇文章主要為大家詳細(xì)介紹了Android應(yīng)用創(chuàng)建桌面快捷方式代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
Android編程自定義AlertDialog樣式的方法詳解
這篇文章主要介紹了Android編程自定義AlertDialog樣式的方法,結(jié)合實(shí)例形式詳細(xì)分析了Android自定義AlertDialog樣式的具體布局與功能實(shí)現(xiàn)相關(guān)操作技巧,需要的朋友可以參考下2018-02-02
Android指紋識(shí)別API講解,一種更快更好的用戶體驗(yàn)
今天小編就為大家分享一篇關(guān)于Android指紋識(shí)別API講解,一種更快更好的用戶體驗(yàn),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10
android JSON解析數(shù)據(jù) android解析天氣預(yù)報(bào)
這篇文章主要為大家詳細(xì)介紹了android JSON解析數(shù)據(jù),android天氣預(yù)報(bào)JSON數(shù)據(jù)解析,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03

