Android进阶之路Android开发经验谈Android开发

WebView-Android与H5交互、设置cookie、po

2017-12-28  本文已影响11人  喂_balabala
mWbRealize.loadUrl("http://652857502.scene.eqxiu.com/s/vknb0n8W?eqrcode=1&from=singlemessage&isappinstalled=0");
//支持javascript
web.getSettings().setJavaScriptEnabled(true); 
// 设置可以支持缩放 
web.getSettings().setSupportZoom(true); 
// 设置出现缩放工具 
web.getSettings().setBuiltInZoomControls(true);
//扩大比例的缩放
web.getSettings().setUseWideViewPort(true);//让webview读取网页设置的viewport,pc版网页 
//自适应屏幕
web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);//适应屏幕,内容将自动缩放  
webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);//适应内容大小  
web.getSettings().setLoadWithOverviewMode(true);
settings.setDomStorageEnabled(true);//打开DOM储存API
settings.setBlockNetworkImage(true);//拦截图片的加载
web.setInitialScale(25);//为25%,最小缩放等级 

// 设置缓存模式:不使用缓存
 mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
// 设置启动缓存  
 webView.getSettings().setDefaultTextEncodingName("utf-8");  
 webView.getSettings().setAppCacheEnabled(true);
 webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);  

postUrl

//需要访问的网址  
String url = "http://www.cqjg.gov.cn/netcar/FindThree.aspx";  
//post访问需要提交的参数  
String postDate = "txtName=zzz&QueryTypeLst=1&CertificateTxt=dsds";  
//由于webView.postUrl(url, postData)中 postData类型为byte[] ,  
//通过EncodingUtils.getBytes(data, charset)方法进行转换  
webView.postUrl(url, EncodingUtils.getBytes(postDate, "UTF-8"));  

EncodingUtils是 HttpCore里面的,要加依赖
compile 'org.apache.httpcomponents:httpcore:4.4.4'
网页只加载出一部分,下面就不加载了?
  ● I/chromium(27693): [INFO:CONSOLE(8)] “Uncaught TypeError: Cannot call method ‘getItem’ of null”, source: url
网页加载不完成并报出如上错误时,有可能是你的DOM储存API没有打开,在代码中加上一行:
mWebView.getSettings().setDomStorageEnabled(true);

如果希望点击链接由自己处理,而不是新开Android的系统browser中响应该链接。给WebView加一个事件监听对象(WebViewClient)并重写其中的一些方法:shouldOverrideUrlLoading:对网页中超链接按钮的响应。当按下某个连接时WebViewClient会调用这个方法,并传递参数:按下的url。

webView.setWebViewClient(new WebViewClient(){
         @Override
         public boolean shouldOverrideUrlLoading(WebView view, String url) {
 
          view.loadUrl(url);   //在当前的webview中跳转到新的url
 //如果不需要其他对点击链接事件的处理返回true,否则返回false
          return true;
         }
   @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

            if (url.startsWith("http") || url.startsWith("https")) { //http和https协议开头的执行正常的流程
                return super.shouldInterceptRequest(view, url);
            } else {  //其他的URL则会开启一个Acitity然后去调用原生APP

                if (url.contains("mqqwpa")){


                    if (OthersUtil.isQQClientAvailable(mContext)){

                        Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                        startActivity(in);
                        return null;
                    }else {

//                        Toast.makeText(mContext, "您的手机未安装手机QQ", Toast.LENGTH_SHORT).show();
//                        return super.shouldInterceptRequest(view, url);
                        return null;
                    }
                }

                Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                startActivity(in);
                return null;
            }
        }
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
//            showErrorPage();//显示错误页面
            hideErrorPage();
        };
        public void onPageFinished(WebView view, String url) {//处理网页加载成功时
//            loading_over.setVisibility(View.GONE);
//            hideErrorPage();
        }
//监听webview界面切换
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
    super.onPageStarted(view, url, favicon);
    if (url.contains("https://www.hzjr.com/Mobile/Index/customer?token=")){
        mCloseService.setVisibility(View.GONE);
    }
}
        });

onReceivedError 不能捕捉失败的回调???

onReceivedError 有两个重载的方法,要重写第二个

1、public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {

2、 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {

点击超链接启动QQ

mWebView = (ProgressWebView) findViewById(R.id.baseweb_webview); mWebView.getSettings().setJavaScriptEnabled(true); String url ="http://wpa.qq.com/msgrd?v=3&uin=748895431&site=qq&menu=yes"; mWebView.loadUrl(url); mWebView.setWebViewClient(new WebViewClient() { 
public boolean shouldOverrideUrlLoading(WebView view, String url) {
 view.loadUrl(url); return true;
 } 
@Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
 if (url.startsWith("http") || url.startsWith("https")) {
 //http和https协议开头的执行正常的流程 return super.shouldInterceptRequest(view, url); 
} else { 
//其他的URL则会开启一个Acitity然后去调用原生APP Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(in); return null;
 }
 }
 });

滑动监听

自定义webview重写onScrollChanged方法,利用接口回调

public class HzjrWebView extends WebView {
    private OnScrollChangedCallback mOnScrollChangedCallback;
    public HzjrWebView(Context context) {
        super(context);
    }

    public HzjrWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public HzjrWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onScrollChanged(final int l, final int t, final int oldl,
                                   final int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);

        if (mOnScrollChangedCallback != null) {
            mOnScrollChangedCallback.onScroll(l , oldl, t , oldt);

        }
    }

//    public OnScrollChangedCallback getOnScrollChangedCallback() {
//        return mOnScrollChangedCallback;
//    }

    public void setOnScrollChangedCallback(
            final OnScrollChangedCallback onScrollChangedCallback) {
        mOnScrollChangedCallback = onScrollChangedCallback;
    }

    /**
     * Impliment in the activity/fragment/view that you want to listen to the webview
     */
    public interface OnScrollChangedCallback {
         void onScroll(int l,int oldl,int t, int oldt);
    }
}

页面关闭之后,视频或者音频还在播放的问题

方法1:
调用
 webView.loadUrl("about:blank");
这个方法会 销毁所有的video和audio 包括js的所有正在运行的function
方法2:
@Override
public void onPause() {
    super.onPause();
    myWebView.onPause();
    myWebView.pauseTimers();
}

@Override
public void onResume() {
    super.onResume();
    myWebView.resumeTimers();
    myWebView.onResume();
}


@Override
protected void onDestroy() {
    myWebView.destroy();
    myWebView = null;
    super.onDestroy();
}

复写生命周期的方法;最好的方法;(有时会挂 java.lang.IllegalArgumentException: Receiver not registered: android.widget.ZoomButtonsController$1@3ed4bcc7)

要在销毁之前把根布局的所有子布局remove

mLlH5.removeAllViews();

回退时回到上一个页面,而不是退出WebView

mWebView.goBack(); //后退 
mWebView.goForward();//前进 
mWebView.reload(); //刷新
public class MainActivity extends Activity {
    private WebView webview;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //2、在Activity中实例化WebView
        setContentView(R.layout.activity_main);
        webview = (WebView) findViewById(R.id.webview);

        //第2步也可以替换为下面这两句,就不要R.layout.activity_main布局文件了
        //mwebview = new WebView(this);                       //实例化WebView对象  
        //setContentView(mwebview); 

        // 设置WebView属性,能够执行Javascript脚本
        webview.getSettings().setJavaScriptEnabled(true);
        //3、 加载需要显示的网页
        webview.loadUrl("http://www.baidu.com/");
        ///4、设置响应超链接,在安卓5.0系统,不使用下面语句超链接也是正常的,但在MIUI中安卓4.4.4中需要使用下面这条语句,才能响应超链接
        webview.setWebViewClient(new HelloWebViewClient());
    }

    @Override
    // 设置回退
    // 5、覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法
    public boolean onKeyDown(int keyCode, KeyEvent event) {
           //按下返回键并且webview界面可以返回
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) {

            webview.goBack(); // goBack()表示返回WebView的上一页面
            return true;
        }
        return super.onKeyDown(keyCode,event);
    }

    // Web视图
    private class HelloWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }
}

设置cookie

ATTENTION:
    要在webView设置setting之后,loadUrl之前调用此方法,否则无效
    
    关于设置cookie失效的问题,在5.0以下可能会有失效的情况,sync是异步操作。
    失效的原因是在removeSessionCookie之后立马setCookie可能会是设置之后又被清除了,可以加个延迟。
    在5.0以上官方回调了同步方法。
    具体介绍参考博客:https://blog.csdn.net/b275518834/article/details/51004237
    /**
     * 给WebView同步Cookie
     *
     * @param context 上下文
     * @param url     可以使用[domain][host]
     */
    private void syncCookie(Context context, String url) {
        CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);
//        cookieManager.removeSessionCookie();// 移除旧的[可以省略]
        cookieManager.setCookie(url,cookie);
        CookieSyncManager.getInstance().sync();// To get instant sync instead of waiting for the timer to trigger, the host can call this.
    }

还有权限:

<uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

H5与Android交互

首先最重要最容易忽略的网络权限
public class MainActivity extends AppCompatActivity {

/***************************************************************
 * H5和Android通信三种方式
 * 1.android主动调用js:javascript:方法名(参数)
 * 2.js主动调用Android
 * 3.js callback式调用Android,来源(解耦H5只关心H5,客户端只关心android)
 * ***************************************************************
 */

private WebView mWebview;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();

    //设置webview
    WebSettings settings = mWebview.getSettings();
    settings.setJavaScriptEnabled(true);

    //页面加载完成调用js方法
    //重新浏览器内核对象
    initWebClient();

    //js和Android两种不同开发语言,不认识
    //核心方法:设置js和Android通信桥梁接口(简而言之,就是设置通信桥梁类)
    JavascriptMethos jsMethos = new JavascriptMethos(this, mWebview);
    //参数1:提供给js调用的方法的对象, 参数2:参数1的映射字符串(第一个参数的别名),因为字符串再所有开发一样通用
    mWebview.addJavascriptInterface(jsMethos, JavascriptMethos.JSINTERFACE);

    //显示
    mWebview.loadUrl("http:/10.0.3.2:8080/html35/index.html");
}

private void initWebClient() {
    mWebview.setWebChromeClient(new WebChromeClient());


    mWebview.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }

        //页面加载完成调用该方法
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            //调用js 方法
            //WebView.loadUrl("javascript:方法名(参数)")
            JSONObject json = new JSONObject();
            try {
                json.put("name", "android");
                json.put("msg", "你好,我是Android,加个蚝友");
                mWebview.loadUrl("javascript:receiveMessage("+json.toString()+")");
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    });
}

    private void initView() {
        mWebview = (WebView) findViewById(R.id.webview);
    }
}



/**
 * 统一管理所有js和Android通信
 * 
 */

public class JavascriptMethos {

    public static String JSINTERFACE = "jsInterface";
    private Context mContext;
    private WebView mWebView;

    public JavascriptMethos(Context mContext, WebView mWebView) {
        this.mContext = mContext;
        this.mWebView = mWebView;
}

/**
 * 给js调用的弹出toast方法
 * 为什么要添加注解:android4.2以上(包含),如果不加注解,
 * js无法调用Android方法,因为4.2之前js和android通信有安全问题,如果不加上该注解,4.2以上js无法调用Android方法
 *
 * @param json
 */
@JavascriptInterface
public void showToast(String json) {
    Toast.makeText(mContext, json, Toast.LENGTH_SHORT).show();
}

@JavascriptInterface
public void getHotelData(String json) throws JSONException {

    //解析callbak方法名
    JSONObject jsJson = new JSONObject(json);
    final String callback = jsJson.optString("callback");

    System.out.println("接收到js传递callback参数=" + json);
    //模拟访问网络
    //返回json
    final JSONObject callbackJson = new JSONObject();
    try {
        callbackJson.put("name", "8天连锁酒店");
        callbackJson.put("hotel", "99");
        callbackJson.put("phone", "075588888888");

        //调用js方法
        //mWebView.loadUrl("javascript:方法名(参数)");默认Android调用js独立运行在一个进程WebViewCoreThread
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                //mWebView.loadUrl("javascript:receiveHotelData(" + callbackJson.toString() + ")");
                mWebView.loadUrl("javascript:"+callback+"(" + callbackJson.toString() + ")");
            }
        });
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

    private Handler mHandler = new Handler();
}
demo

https://github.com/jiaweizeng/H5AndAndroid

control是java对象名称,toastMessage是方法名称,双方约定俗成,写死。

<body>
    <button type="button" id="button" onclick="toastMessage('js调用了android方法')">js访问android中方法</button>
    <script>
        function toastMessage(message) {
            window.control.toastMessage(message)
        }  
    </script>
</body>


public class MainActivity extends AppCompatActivity {

    @SuppressLint({"JavascriptInterface", "AddJavascriptInterface", "SetJavaScriptEnabled"})
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        WebView webView = findViewById(R.id.wv);

        WebSettings webSettings = webView.getSettings();

        webSettings.setJavaScriptEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webView.loadUrl("http://192.168.1.38/hzjrH5/jiaohu.html");
        //js访问android,定义接口
        webView.addJavascriptInterface(this, "control");
    }

    @JavascriptInterface
    public void toastMessage(String s){
        Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
        finish();
    }
}
上一篇下一篇

猜你喜欢

热点阅读