现在很多app都是跟web页面混编的。除了原生控件以外,有些功能页面直接用web端的,用webview加载后台同事写的功能,避免重复开发。但是webview加载远程url速度会比较慢,也比较影响用户体验,有些公司产品经理会要求使用html和css、js、jpg等都用本地的来读取,webview只需要加载远程数据,这样既节省了流量,也会大大提升运行速度。

但是这就有两个问题了:

①登陆问题

②访问url如何加载本地web资源

最近做项目的时候,遇到了这个需求,webview加载本地资源,国内帖子少之又少,这个问题辗转了一个多星期,才得以解决,现在把主要的核心代码贴出来,以便后人查阅



//登陆获取session,保存起来,之后然后同步session就可以实现登陆了
RequestParams params = new RequestParams("你的登陆地址"); 
HashMap
   
   
    
     signMap = new HashMap
    
    
     
     (); 
params.addBodyParameter("json", url_post);//json里面包含自己的用户名、加密的密码等信息

//发送到后台验证,我这里是使用xutil3 做请求,也可以改成自己的
x.http().post(params, new Callback.CacheCallback
     
     
      
      () {
            @Override
            public boolean onCache(String result) {
                return false;
            }

            @Override
            public void onSuccess(String result) {
                Log.e("--------发送到服务器接收成功!!!!!!!!!!!!!", "result:" + result + "");
                //Toast.makeText(context, result + "", Toast.LENGTH_LONG).show();

                //-----------------------获取session-----------------------//
                DbCookieStore instance = DbCookieStore.INSTANCE;
                List
      
      
       
        cookies = instance.getCookies();
                for (int i = 0; i < cookies.size(); i++) {
                    //保存session
                    HttpCookie cookie = cookies.get(i);
                    MyCookieStore.cookies = cookie;
                    if ((cookies.get(i) + "").contains("JSESSIONID")) {
                        MyCookieStore.SessionId = cookies.get(i).toString().replace("JSESSIONID=", "");
                        break;
                    }
                }
                //-----------------------获取session-----------------------//

                //我们的服务器返回成功啦!正式进入登陆主界面
                Intent intent = new Intent(context, MainActivity.class);
                context.startActivity(intent);
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {

            }

            @Override
            public void onCancelled(CancelledException cex) {

            }

            @Override
            public void onFinished() {

            }
        });




//保存cookie的类
public class MyCookieStore {
    public static CookieStore cookieStore=null;
    public static HttpCookie cookies=null;
    public static String SessionId = "";
}




//主MainActivity
public class MainActivity extends Activity{
    private Webview webview;
    private BMHWebViewClient mBMHWebViewClient;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //webview = (WebView) root.findViewById(R.id.wv_mainui);
        WebSettings webSettings = webview.getSettings();
        webSettings.setDefaultTextEncodingName("GBK");//设置字符编码
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setAllowFileAccess(true);// 设置允许访问文件数据
        webSettings.setAllowContentAccess(true);
        webSettings.setSupportZoom(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        webSettings.setAppCacheEnabled(true);
        webSettings.setDatabaseEnabled(true);
        webSettings.setJavaScriptEnabled(true);//滚动条风格,为0指滚动条不占用空间,直接覆盖在网页上
        mBMHWebViewClient = new BMHWebViewClient(this);
        webview.setWebViewClient(mBMHWebViewClient);//网页跳转监听
        
        String mainUrl = "htpp://192.168.1.1/html/index/index.html"";//url远程地址,改成你的域名

        webview.loadUrl(mainUrl);
        CookieUtil.syncCookie(getContext(), mainUrl);//同步session实现登陆
        }
    }




public class BMHWebViewClient extends WebViewClient {

    private Activity activity;//当前的活动类

    /**
     * 监听webview的跳转链接,处理连接本地化、过滤地址
     *
     * @param activity 活动页上下文
     */
    public BMHWebViewClient(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {

    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {

    }

//webview每次访问html、css、图片、js、font资源的时候,都回来这里过滤,在这个方法里面,把本需要远程访问的资源,替换成本地读取
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, final String url) {
        WebResourceResponse response = null;

            try {
                String newUrl;//本地的路径
                newUrl = url.replace(activity.getString(R.string.url_head), activity.getFilesDir().getPath());//url_head域名,把远程地址替换成files文件夹下的对应资源,如:远程地址需要加载:url是http://www.baidu.com/html/index.html,newUrl就为:/data/data/包名/files/html/index.html
                //Log.v("NEWURL--------------------------->",newUrl);

                //请求不同的远程资源,生成不同类型的文件返回。
                String type;
                if (newUrl.contains(".js")) {
                    type = "text/javascript";
                } else if (newUrl.contains(".png")) {
                    type = "image/png";
                } else if (newUrl.contains(".html")) {
                    type = "text/html";
                } else if (newUrl.contains(".css")) {
                    type = "text/css";
                } else if (newUrl.contains(".jpg")) {
                    type = "image/jpeg";
                } else {
                    return null;
                }
                FileInputStream input = new FileInputStream(newUrl);
                response = new WebResourceResponse(type, "UTF-8", input);
            } catch (IOException e) {
                //e.printStackTrace();
            }         
        //如果返回null,webview继续访问远程的资源,非null使用本地的资源,不再从远程取
        return response;
    }




public class CookieUtil {
    /**
     * 将cookie同步到WebView
     *
     * @param context 上下文
     * @param url     WebView要加载的url
     */
    public static void syncCookie(Context context, String url) {
        try {
            CookieSyncManager syncManager = CookieSyncManager.createInstance(ZebraApplication.getContext());
            CookieManager cookieManager = CookieManager.getInstance();
            cookieManager.setAcceptCookie(true);
            cookieManager.removeAllCookie();
            String host = ZebraApplication.getContext().getResources().getString(R.string.url_head);
            cookieManager.setCookie(host, "JSESSIONID="+ MyCookieStore.SessionId);
            syncManager.sync();
            String newCookie = cookieManager.getCookie(url);

        } catch (Exception e) {
            Log.e("Nat: webView.syncCookie failed", e.toString());
        }
    }
}




PS:android的assets文件夹是只读的。在app第一次启动的时候,把assets里面的文件夹下的资源全部复制到包名下的fiels文件夹,我这里是在assets下放一个压缩包,执行解压到程序下的fiels文件夹里。进行维护。每次启动发现webview资源更新了,执行下载覆盖files下的对应文件即可。