大家好,我是一个默默无闻的小Android搬运工。
最近,领导问我,小伙子忙不忙啊,公司要做幼儿编程,你准备一下吧。
我说怎么回事,领导给我发了个编程猫APP,就按照这个做。
我一看,哦,以前没研究过啊,这是什么鬼,然后前端小伙伴给了我一个本地HTML代码,我一看,so easy啊,这不就是webview加载本地HTML么,5分钟就能结束。
说做就做,小代码咔咔一写
webview.loadurl("file:///android_asset/html/index.html")
很快啊,啪,项目运行起来了,点一点,诶,能点,看来可以了,再点一点,诶,这个保存怎么没反应,这个打开文件怎么没反应
这就让我这个CV工程师脸没处放了,那必须得解决了,一步一步来
1.保存文件->下载blob类型文件
[img]http://chuantu.xyz/t6/741/1613038816x2073530471.png
-配置webview
webSettings.defaultTextEncodingName = "utf-8" //设置编码
webSettings.cacheMode = WebSettings.LOAD_DEFAULT //设置缓存策略
webSettings.javaScriptEnabled = true //启用js(重要)
webSettings.loadWithOverviewMode = true //是否使用概览模式
webSettings.useWideViewPort = true //设置屏幕自适应
-添加下载回调
web.setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
//下载代码
}
此回调会返回下载url
-注入js代码(重头戏,)
首先js代码
request.open('GET', '" + url + "', true);
request.setRequestHeader('Content-type', 'text/plain');
request.responseType = 'blob';
request.onload = function (e) {
if (this.status === 200) {
var blobFile = this.response;
var reader = new FileReader();
reader.readAsDataURL(blobFile);
reader.onloadend = function() {
var base64data = reader.result;
window.java.down(base64data);
}
}
};
request.send();
只需要把url传进去就好了
完整代码
val blob = " var request = new XMLHttpRequest();" +
" request.open('GET', '" + url + "', true);" +
" request.setRequestHeader('Content-type', 'text/plain');" +
" request.responseType = 'blob';" +
" request.onload = function (e) {" +
" if (this.status === 200) {" +
" var blobFile = this.response;" +
" var reader = new FileReader();" +
" reader.readAsDataURL(blobFile);" +
" reader.onloadend = function() {" +
" var base64data = reader.result;" +
" window.java.down(base64data);" +
" }" +
" }" +
" };" +
" request.send();"
val js = "javascript:$blob"
web.evaluateJavascript(js,null) //注入js代码并执行
web.addJavascriptInterface(object : Any() {
@JavascriptInterface
fun down(base64: String?) {
//得到下载的base64字符串,需自行转换
}
}, "java")
2.上传文件,打开文件管理器
webview配置如上
-重写WebChromeClient
class ZpWebChromeClient : WebChromeClient() {
private var mOpenFileChooserCallBack: OpenFileChooserCallBack? = null
//For Android 3.0 - 4.0
// For Android < 3.0
@JvmOverloads
fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String = "") {
if (mOpenFileChooserCallBack != null) {
mOpenFileChooserCallBack!!.openFileChooserCallBack(uploadMsg, acceptType)
}
}
// For Android 4.0 - 5.0
fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String, capture: String) {
openFileChooser(uploadMsg, acceptType)
}
override fun onConsoleMessage(cm: ConsoleMessage?): Boolean {
println(("JavaScript log, " + cm!!.sourceId() + ":" + cm.lineNumber() + ", " + cm.message()))
return true
}
// For Android > 5.0
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams): Boolean {
if (mOpenFileChooserCallBack != null) {
mOpenFileChooserCallBack!!.showFileChooserCallBack(filePathCallback, fileChooserParams)
}
return true
}
fun setOpenFileChooserCallBack(callBack: OpenFileChooserCallBack?) {
mOpenFileChooserCallBack = callBack
}
override fun onProgressChanged(view: WebView, newProgress: Int) {
super.onProgressChanged(view, newProgress)
}
interface OpenFileChooserCallBack {
fun openFileChooserCallBack(uploadMsg: ValueCallback<Uri>, acceptType: String) //打开文件选择回调
fun showFileChooserCallBack(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams) //选择文件回调
}
Activity实现ZpWebChromeClient.OpenFileChooserCallBack并设置webview.setwebChromeClient,然后自行处理文件选择就可,别忘了在onActivityResult获取回调
调用手机摄像头
此处就比较简单了,js配置依旧如上
在自定义WebChromeClient中添加onPermissionRequest,然后activity中会调用增加拦截权限代码
/* access modifiers changed from: private */
fun requestCameraPermissions(permissionRequest2: PermissionRequest) {
mViewModel.permissionRequest = permissionRequest2
val arrayList = ArrayList<Any>()
for (str in permissionRequest2.resources) {
if (str == "android.webkit.resource.VIDEO_CAPTURE" && ContextCompat.checkSelfPermission(
this,
mViewModel.ANDROID_PERMISSION_CAMERA
) != 0
) {
arrayList.add(mViewModel.ANDROID_PERMISSION_CAMERA)
}
if (str == "android.webkit.resource.AUDIO_CAPTURE" && ContextCompat.checkSelfPermission(
this,
mViewModel.ANDROID_PERMISSION_RECORD_AUDIO
) != 0
) {
arrayList.add(mViewModel.ANDROID_PERMISSION_RECORD_AUDIO)
}
}
if (!arrayList.isEmpty()) {
ActivityCompat.requestPermissions(
this,
(arrayList.toArray(arrayOfNulls<String>(arrayList.size)) as Array<String?>),
2
)
} else {
grantPermission()
}
}
private fun grantPermission() {
val permissionRequest2: PermissionRequest =
mViewModel.permissionRequest as PermissionRequest
permissionRequest2.grant(permissionRequest2.resources)
mViewModel.permissionRequest = null
}
此段代码即可调用摄像头
手动向webview添加header信息
虽然现在webview支持自动添加头部信息,但是,拦不住特殊需求啊,产品非要略过登录直接到下一步,没得办法只能手动添加header了。
-依旧是启用js
-注入js
在WebViewClient的onPageFinished方法中添加js代码
val key = "pro__Access-Token"
val js = "window.localStorage.setItem('$key','${
mViewModel.local(let {
PreferenceUtils.getString(
this@WriteActivity,
"token"
)
} as String)
}');"
view.evaluateJavascript(js) { value: String ->
println(
"localStorage:$value"
)
}
需要注意的是,代码中的key值和value值需要和前端沟通,规定好要什么给什么
网友评论