最近做了一个关于webview写安卓的壳,套HTML5的应用,虽然整个写下来后,到了目前的进度,代码量不多,共有1000多行,但是整个壳的设计思想和实现思路还是当初查了很久的。所以写下来,以备后续查看和分享。
这个webview的壳目前实现的功能我将从三方面说明并总结。
1. 最基本的功能:
- 增加useragent以便HTML5判断出是哪个应用
- 设置webSetting缓存
- 拦截url并将相应网络资源替换成本地资源
- javascript和android交互
- 网络状态监听
- HTML进度条替换成Android原生进度条,以及onPageFinished中遇到的坑
- 口语评测打分
- 下载资源包并在本地解压,本地MP3的播放、暂停以及退出并返回当前的播放进度。
- 本地录音并存储为PCM格式,本地PCM的播放
- 消息推送功能
下面进行详细说明:
- 最基本的功能
- 增加useragent以便HTML5判断出是哪个应用(android或者ios)(这里的android_agent和HTML商量好就可以)
WebSettings webSettings = webView.getSettings();
String ua = webSettings.getUserAgentString();
webSettings.setUserAgentString(ua + getString(R.string.android_agent));
- 设置webSettting缓存
- 拦截url并将相应网络资源替换成本地资源
我们将一些固定不变的图片放到工程的assets文件下,然后拦截网络的url进行替换,这样用户在第一次进入界面时,就不会因为加载图片而花费较长时间,造成用户体验不好,但是如果拦截到相应的的url时间长了,页面依旧会加载比较长的时间,但这个Android就无能为力了。
拦截替换函数如下:
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("start", url);
}
@Override
public void onLoadResource(WebView view, String url) {
Log.e("cache", "onLoadResource-url=" + url);
super.onLoadResource(view, url);
}
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
WebResourceResponse response = null;
Log.d("Webview", "shouldInterceptRequest url=" + url);
if (url.contains("ajax.php") && !Validate.isNetworkConnected(Webview.this)) {
//网络连接不可用时并且拦截到ajax时
}
if (url.contains("http://emodou.com/resource/be")) {
//三种中的第一种,替换资源文件
String path = url.substring(17, url.length());
File file = new File(Constants.STORAGE_URL_START + path);//path: /resource/be/e_Res/BF1/22101/res/1.jpg
Log.d("path", path);
FileInputStream fin = null;
try {
fin = new FileInputStream(file);
//进行"/"分割
String[] urlArray = url.split("/");
int urlCount = urlArray.length;
Log.d("count", urlCount + "");
//进行"."分割
String suffixes = urlArray[urlCount - 1];
String[] suffixesArray = suffixes.split("\\.");
int suCount = suffixesArray.length;
//如果遇到后缀名符合的,进行拦截替换
if (suffixesArray[suCount - 1].equals("jpg") ||
suffixesArray[suCount - 1].equals("png") ||
suffixesArray[suCount - 1].equals("jpeg") ||
suffixesArray[suCount - 1].equals("JPG") ||
suffixesArray[suCount - 1].equals("PNG") ||
suffixesArray[suCount - 1].equals("JPEG")) {
response = new WebResourceResponse("image/png", "UTF-8", fin);
} else if (suffixesArray[suCount - 1].equals("mp3") ||
suffixesArray[suCount - 1].equals("MP3")) {
response = new WebResourceResponse("audio/mpeg", "UTF-8", fin);//mp3替换不到
} else if (suffixesArray[suCount - 1].equals("JSON") ||
suffixesArray[suCount - 1].equals("json")) {
response = new WebResourceResponse("application/json", "UTF-8", fin);
} else if (suffixesArray[suCount - 1].equals("lrc") ||
suffixesArray[suCount - 1].equals("LRC")) {
response = new WebResourceResponse("text/plain", "UTF-8", fin);
} else if (suffixesArray[suCount - 1].equals("mp4") ||
suffixesArray[suCount - 1].equals("MP4")) {
response = new WebResourceResponse("video/mp4", "UTF-8", fin);
} else if (suffixesArray[suCount - 1].equals("vtt") ||
suffixesArray[suCount - 1].equals("VTT")) {
response = new WebResourceResponse("text/vtt", "UTF-8", fin);
}
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
}
return response;
}
});
- js和android交互
webView.loadUrl("javascript:DM.progress("+percent+")");
其中DM.progress是HTML的方法,percent是android需要传过去的参数,其他为固定内容。
js调用android的代码方法:
webView.addJavascriptInterface(new JsToJava(), "record");
JsToJava()是android里面自己写的类,这个类中所有的函数都可以被JS以window.record.XX(); 方式调用,其中XX是函数名。需要特别注意的是XX函数上要添加@SuppressLint("JavascriptInterface"),否则调用会无响应
@SuppressLint("JavascriptInterface") public void initWebView() {
}
2.增加用户体验的功能
- 网络状态的监听
- HTML进度条替换成Android原生进度条,以及onPageFinished中遇到的坑
public class TimeControlTask extends AsyncTask
{
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
av.setVisibility(View.GONE);
webView.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(Integer... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
然后在onPageFinished函数中进行调用即可
new TimeControlTask().execute();
- 口语评测打分,采用的科大讯飞语音打分的技术,具体请点开超链接,参考文档。
- 下载资源包并在本地解压,本地MP3的播放、暂停以及退出并返回当前的播放进度。这里需要说明的是,下载资源包使用的是OKHttpUtils
- 消息推送功能,集成的是友盟的推送。
暂时功能模块如上所述,如果有更新新功能,还会回头来补充这篇文章。