最近开发一个Web壳app,我用的是Webview加载前端页面,本来应该是挺简单的事,但是开发过程中Webview的坑还是比较多(IOS一点事都没有,只能说搞Android的命苦),在这总结一下:
主要原因:A:在Android 4.4以下(不包含4.4)系统WebView底层实现是采用WebKit(http://www.webkit.org/)内核,而在Android 4.4及其以上Google 采用了chromium(http://www.chromium.org/)作为系统WebView的底层内核支持。
B:部分WebView的API在不同的Android版本中不同,所以需要去适配不同的版本,贼坑。
C:Android对前端的一些标签不支持。
Bug1.在Android4.4版本中Webview定位功能失效,我自己5.0的系统可以定位(Android4.4以下没有去测试)。
原因:Android4.4以下需要我们自己去打开数据库,开启定位。
解决办法:
mWebView.addJavascriptInterface(this, "android"); // 让WebView能够执行javaScript mWebSettings = mWebView.getSettings(); mWebSettings.setJavaScriptEnabled(true); mWebView.getSettings().setDomStorageEnabled(true); //启用数据库 mWebSettings.setDatabaseEnabled(true); String dir = this.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); //启用地理定位 mWebSettings.setGeolocationEnabled(true); //设置定位的数据库路径 mWebSettings.setGeolocationDatabasePath(dir);并且在WevChromeClient中实现:
onGeolocationPermissionsShowPrompt();
Bug2.在上传本地文件不成功
原因:Android对前端的input标签不支持
解决办法:在WevChromeClient中实现以下方法:
private ValueCallback<Uri[]> UploadMessage; public ValueCallback<Uri> mUploadMessage; private static final int KITKAT_RESULTCODE = 99; public static final int REQUEST_SELECT_FILE = 100; public final static int FILECHOOSER_RESULTCODE = 1;
// For Android 3.0 private void openFileChooser(ValueCallback<Uri> uploadMsg) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); } // For Android 3.0+ public void openFileChooser(ValueCallback uploadMsg, String acceptType) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("*/*"); startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE); } //For Android 4.1 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { mUploadMessage = uploadMsg; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE); }
//For Android 5.0+
@Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { UploadMessage = filePathCallback; Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), REQUEST_SELECT_FILE); return true; }
并且在activityResult方法中接收
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onActivityResult(int requestCode, int resultCode,Intent intent) {
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage) return;
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else if (requestCode == REQUEST_SELECT_FILE) {
if (UploadMessage == null) return;
UploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
UploadMessage = null;
} else if (requestCode == KITKAT_RESULTCODE) {
/**
1 上传图片
2 上传成功后 将服务器返回的URL 返回给 js : UploadedFileName
String UploadedFileName = "URL";
mWebView.loadUrl("javascript:CheckImage('" + UploadedFileName + "')");
*/
Uri imgUri = intent.getData();
Toast.makeText(this, "success="+imgUri, Toast.LENGTH_SHORT).show();
String UploadedFileName = imgUri.toString();
mWebView.loadUrl("javascript:CheckImage('" + UploadedFileName + "')");
}
}
Bug3.尽管实现了上述方法上,在Android4.4的机子上任然上传不了图片。
原因:Android4.4取消了webview 上传文件的方法,需要我们自己写一个接口。给js调用
解决办法:(感觉有这一个方法就够了,上面的可以不要,不过我没测试过)
mWebView.addJavascriptInterface(new ModuleJavaScriptInterface(), "$_demo");
mWebView.addJavascriptInterface(new ModuleJavaScriptInterface(), "$_photo");
final class ModuleJavaScriptInterface { ModuleJavaScriptInterface() {} /*android 4.4调用系统相册*/ @JavascriptInterface public void uploadImage() { Toast.makeText(MainNewActivity.this, "upload ", Toast.LENGTH_SHORT).show(); //打开相册 Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "File Chooser"), KITKAT_RESULTCODE); }
Bug4.没办法保持登陆状态
原因:Cookie会失效
解决办法:把用户账号和密码保存到本地,进入app的时候判断一下,本地数据库中有就设置到cookie中去,关联到webview,后台做个判断,自动登陆。
首先:在setWebviewClient的onpageFinished()添加保存账号和密码的代码
CookieSyncManager.createInstance(getApplicationContext()); CookieManager cookieManager = CookieManager.getInstance(); String cookie = cookieManager.getCookie(url);//获取url中的cookie Log.d("zyx", "cookie======" + cookie); String[] cookies = cookie.split(";"); for (int i = 0; i < cookies.length; i++) { String[] nvp = cookies[i].split("="); if (nvp[0].trim().equals("tel")){//保存账号 SharedPreferences sharedPreferences = getSharedPreferences("cookise",Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("tel",nvp[1]); editor.commit(); Log.d("zyx", "===tel===" + nvp[1]); } if (nvp[0].trim().equals("pwd")){//保存密码 SharedPreferences sharedPreferences = getSharedPreferences("cookise",Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("pwd",nvp[1]); editor.commit(); Log.d("zyx", "==pwd====" + nvp[1]); } if (nvp[0].trim().equals("logout")){//删除密码和账号 SharedPreferences sharedPreferences = getSharedPreferences("cookise",Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.clear(); editor.commit(); cookieManager.removeSessionCookie();// 移除cooki cookieManager.removeAllCookie(); Log.d("zyx", "==logout====" + nvp[1]); } Log.d("zyx", "-----nvp:" + nvp[0] + "---->" + nvp[1]); }在webview.loadurl(url)之前调用:
//判断登陆状态
private void islogin(String url){
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeAllCookie();
// cookieManager.setCookie(url, "domain=192.168.1.1"); //域(貌似不设也无所谓)
// cookieManager.setCookie(url, "path=/"); //路径(貌似不设也无所谓)
cookieManager.setCookie(url,"tel="+mTel);
cookieManager.setCookie(url,"pwd="+mPwd); //账号密码
mCookie = cookieManager.getCookie(url);//这里可以获取你的cookie看一下是什么样子的,其实就是拼接起来的string
Log.d("zyx", "-----mCookie:" + mCookie );
CookieSyncManager.getInstance().sync();
}
注:在开发过程中也找过很多资料,看过很多大牛的博客,受益匪浅。这里不一一列出,拜谢!
在开发Android Web壳app时,使用WebView加载前端页面遇到了诸多问题,主要由于Android 4.4以下版本的WebView内核与4.4及以上版本不同,导致API适配困难。在Android 4.4中,Webview的定位功能、文件上传等功能存在bug,需要通过特定方法进行修复。此外,Cookie管理也是问题之一,需要手动维护以确保用户登录状态。

120

被折叠的 条评论
为什么被折叠?



