Showing posts with label WebVIew. Show all posts
Showing posts with label WebVIew. Show all posts

Wednesday, February 24, 2016

Android Webview 的坑

作为Ninja浏览器(mthli/Ninja · GitHub)的开发者,我想我遇到的问题应该具有一些代表性吧。下面说说我比较困惑的几个地方。
  1. WebViewClient.onPageFinished()。你永远无法确定当WebView调用这个方法的时候,网页内容是否真的加载完毕了。当前正在加载的网页产生跳转的时候这个方法可能会被多次调用,StackOverflow上有比较具体的解释(How to listen for a Webview finishing loading a URL in Android?), 但其中列举的解决方法并不完美。所以当你的WebView需要加载各种各样的网页并且需要在页面加载完成时采取一些操作的话,可能WebChromeClient.onProgressChanged()比WebViewClient.onPageFinished()都要靠谱一些。
  2. WebView后台耗电问题。当你的程序调用了WebView加载网页,WebView会自己开启一些线程(?),如果你没有正确地将WebView销毁的话,这些残余的线程(?)会一直在后台运行,由此导致你的应用程序耗电量居高不下。对此我采用的处理方式比较偷懒,简单又粗暴(不建议),即在Activity.onDestroy()中直接调用System.exit(0),使得应用程序完全被移出虚拟机,这样就不会有任何问题了。
  3. 切换WebView闪屏问题。如果你需要在同一个ViewGroup中来回切换不同的WebView(包含了不同的网页内容)的话,你就会发现闪屏是不可避免的。这应该是Android硬件加速的Bug,如果关闭硬件加速这种情况会好很多,但无法获得很好的浏览体验,你会感觉网页滑动的时候一卡一卡的,不跟手。
  4. 数据积累问题。开启缓存什么的有利于网页的浏览体验,但你会发现即使是清除了必要的内容,比如Cache、Cookie、Form Data、History、Password等等东西,你的应用程序所占用的存储空间还是会越来越大,到最后只好手动到系统设置的应用信息界面里清除数据了 :(
  5. 滚动条问题。Android System WebView的横向滚动条真是好粗的有木有...
以上是我能想到的啦,没想到的大概是不重要所以自动忽略啦~
另外针对Android System WebView的相关开发,推荐看看Google官方的示例教程 GoogleChrome/chromium-webview-samples · GitHub

PS:我开发Android刚刚满一年,如有疏漏请多多指教 :)

Tuesday, November 17, 2015

Android WebView 与 Javascript 遇到的坑!

Android 中的webview  和 JavaScript 的交互是必不可少的?

================================================================


但是交互的时候我们需要注意:

        //Js callback
        String result = "{\"lat\":\"" + mLatitude + "\",\"lng\":\"" + mLongitude + "\"}";
        String callBack = "javascript:geoCallback(\'" + result + "\')";
        mWebView.loadUrl(callBack);

   注意:
   当我们调用  javascript:geoCallback()
   当你需要传递参数给前台的时候,我们这里传递的参数;

问题:
   A     当传递  Json Object 的时候 最外层 必须用  单引号 包裹, 如果用双引号,前台的js会报错。获取不到数据,这个可能是前台用的框架的原因。
   B     当传递  Json String 的时候,最外层必须用 双引号,



================================================================


webview.LoadUrl()   必须放在主线程,在子线程会报错的!


================================================================


webview setting
配置篇

protected void initWebViewSetting() {
    WebSettings webSettings = mWebView.getSettings();    if(null != webSettings){
        //Tells the WebView to enable JavaScript execution.   The default is false        webSettings.setJavaScriptEnabled(true);        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);        //存储一些简单的用key/value对即可解决的数据,根据作用范围的不同,有Session        //Storage和Local Storage两种,分别用于会话级别的存储(页面关闭即消失)和本地化存储(除非主动        //删除,否则数据永远不会过期)        webSettings.setDomStorageEnabled(true);        //我们能够有选择的缓冲web浏览器中所有的东西,从页面、图片到脚本、css等等        webSettings.setAppCacheEnabled(true);
        webSettings.setSaveFormData(true);
        //设置布局方式        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);        //Sets whether the WebView whether supports multiple windows.        webSettings.setSupportMultipleWindows(true);        //设置webview 缓存模式        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);        //启用或禁用WebView访问文件数据        webSettings.setAllowFileAccess(true);        //节点的获取焦点,当调用 WebView#requestFocus        webSettings.setNeedInitialFocus(true);        webSettings.setLoadWithOverviewMode(true);        //webview是否需要加载图片        webSettings.setLoadsImagesAutomatically(true);        webSettings.setLoadWithOverviewMode(true);        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);        //启动硬件加速        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);        }

        setWebviewJsSetting(mWebView);
        setWebviewExtendSetting(webSettings);
    }
}

/** * 如果需要给Webview 添加设置属性的时候就调用该方法 * * 一般在BaseWebViewActivity设置的setting 满足大多数的情况 * * @param webviewSetting */protected void setWebviewExtendSetting(WebSettings webviewSetting){

}


@Overrideprotected void setWebviewJsSetting(WebView webView) {
    ERPWebViewJsInterface erpWebViewJsInterface = new ERPWebViewJsInterface(this);    erpWebViewJsInterface.setmWebViewJSCallBack(this);    webView.addJavascriptInterface(erpWebViewJsInterface, WebViewParams.WEBVIEWW_JS_FLAG);}


package com.eallcn.rentagent.webview.webinterface;
import android.content.Intent;import android.net.Uri;import android.text.TextUtils;import android.webkit.JavascriptInterface;
import com.baidu.mapapi.model.LatLng;import com.eallcn.rentagent.ui.activity.ERPWebContainerActivity;import com.eallcn.rentagent.ui.control.NavigateManager;
/** * Created by Hades on 11/12/15. */public class ERPWebViewJsInterface extends WebViewJSInterface {

    private ERPWebContainerActivity mContext;
    public ERPWebViewJsInterface(ERPWebContainerActivity context) {
        super(context);        this.mContext = context;    }

    @JavascriptInterface    @Override    public void close() {
        mContext.close();    }

    @JavascriptInterface    public void onCall(String mobile){
        Intent intent = new Intent();        intent.setAction("android.intent.action.CALL");        intent.setData(Uri.parse("tel:" + mobile));        mContext.startActivity(intent);    }

    @JavascriptInterface    public void onSendMessage(String mobile,String content){
        Uri uri = Uri.parse("smsto:" + mobile);        Intent sendIntent = new Intent(Intent.ACTION_VIEW, uri);        content = TextUtils.isEmpty(content)?"":content;        sendIntent.putExtra("sms_body", content);        mContext.startActivity(sendIntent);    }

    /**     * 获取地理位置     */    @JavascriptInterface    public void getLocationInfo(){
        mContext.getLocationInfo();    }

    /**     * 调用app签名signature     *     * type 定义好类型: 根据前端的类型来处理;     * type=21 代表 收房经纪人进入签名界面     * type=22 代表 经纪人经理进入签名界面     */    @JavascriptInterface    public void invokeSignatureView(String type){
        NavigateManager.goToPaintActivityForResult(mContext, Integer.parseInt(type), ERPWebContainerActivity.TEST_SINGNATURE_FLAG);    }

    /**     * 调用手机通讯录     */    @JavascriptInterface    public void invokeContacts(){
        NavigateManager.gotoContactsActivityForResulr(mContext, ERPWebContainerActivity.TEST_CONTAXTS_REQUEST_CODE);    }

    /**     * 调用地图     */    @JavascriptInterface    public void invokeMap(){
        NavigateManager.MapView.gotoMapHouseActivity(mContext);    }

    /**     * 调用地图 制定坐标     *     * 纬度   lat     * 经度   lng     */    @JavascriptInterface    public void invokeMap(String lat,String lng){
        LatLng latLng = new LatLng(Double.parseDouble(lat),Double.parseDouble(lng));        NavigateManager.MapView.gotoMapHouseActivity(mContext,latLng);    }



}



需要注意的是:

Js 接口对象里面的方法必须是 public 或者是缺省。因为 注解 不可使用 低访问权限!


注解是必须要添加的:
从API 17 以后都要这么做的


  @JavascriptInterface