标签: WebView

Android应用开发 WebView与服务器端的Js交互

Android应用开发 WebView与服务器端的Js交互

*近公司再添加功能的时候,有一部分功能是用的html,在一个浏览器或webview中展示出html即可。当然在这里我们当然用webview控件喽

 

WebApp的好处:

在应用里嵌套web的好处有这么几点,1,跨平台,不仅可以在Android上运行,也可以在iOS上运行,而且样式什么的*对统一,因为都是加载的html,用的都是同一套html

2,修改灵活,容易更新版本。例如大家常看到的app里面的广告页,大多是嵌套的html,这样只要后台替换一下页面的内容,手机端就会改变展现内容,跟新版本也是如此,因为界面什么得成了在服务器端,所以要是想跟新界面什么得,只需要在后台修改在发布即可,不需要用户再重新下载app。这个好处我觉得对ios是有很大帮助的,哈哈,绕开苹果审核嘛,由于html我们可以随意替换,审核时可以把违规的部分隐藏,上线之后就可以随意改了,哈哈,你们懂得。

 

当然,开发webapp当然也有局限,就是网速什么的,这个咱无法改变,这里也不废话。不过在开发中呢,如果只是页面之间的交互的话,我们只需提供一个webview控件即可,

可是要是涉及到和手机设备或软件交互的话(如打开相册,摄像头等等),这就需要我们和页面经行js交互,js交互可以说是双向的,一种是,我们调用页面的,就是调用服务端的js方法,另一个呢则是服务端调用我们Android里面的代码,调用其实很简单,下面说一下怎样调用。

当然我们先等有一个WebView,先创建一个Activity,然后设置布局,穿件WebView,布局和Activity如下:

activity_webview.xml



[html] view plain copy print?在CODE上查看代码片派生到我的代码片
01.<?xml version="1.0" encoding="utf-8"?>  
02.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
03.    android:layout_width="match_parent"  
04.    android:layout_height="match_parent"  
05.    android:orientation="vertical" >  
06.    <WebView   
07.        android:id="@+id/webview"  
08.        android:layout_width="match_parent"  
09.        android:layout_height="match_parent"  
10.        />  
11.  
12.</LinearLayout>  




然后是activity,

WebViewActivity.activity



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import android.app.Activity;  
02.import android.os.Bundle;  
03.import android.webkit.WebSettings;  
04.import android.webkit.WebView;  
05.  
06.public class WebViewActivity extends Activity {  
07.    private static final String url = "http://192.168.30.199:8080/song/test.html";  
08.    private WebView mWebView;  
09.    @Override  
10.    protected void onCreate(Bundle savedInstanceState) {  
11.        super.onCreate(savedInstanceState);  
12.        setContentView(R.layout.activity_webviw);  
13.        initView();  
14.    }  
15.  
16.    private void initView() {  
17.        mWebView = (WebView) findViewById(R.id.webview);  
18.        //或的WebView的Setting  
19.        WebSettings settings = mWebView.getSettings();  
20.        //设置支持js,看方法名字就知道啥意思  
21.        settings.setJavaScriptEnabled(true);  
22.        //加载网页路径  
23.        mWebView.loadUrl(url);  
24.    }  
25.}  




上面就是一个简单的webview,然后很常规的设置属性,然后再加载要加载的页面路径,这样一般就可在网页里面自由点击跳转了,但是要和手机交互的话需要我们写js交互的代码了。

首先说怎样调用服务器端的js方法,很简单,和加载网页路径基本上一样如下:



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.mWebView.loadUrl("javascript:forSmallPhoto()");  




就这么简单的一句话你就可以调用服务器端的js方法了,其中JavaScript:是固定写法forSmallPhoto()则是服务端的js方法名字,这是一个无参数的方法,当然也可以传参,这需要我们拼凑字符串,mWebView.loadUrl("javascript:forSmallPhoto('" + data + "')");其中data就是一个变量,也就是你要传的参数值,当然也可以支持多参数传送,这得看你服务器端的js方法有几个参数了,其实就是我们调用一个方法一样,只不过这个方法是在服务器端的。我们调用服务器js,是为了,当Android完成某些功能后,需要告诉服务器,则我们可以调用js来告诉他我们完成了。

 

在一种就是,服务端调用我们的Android代码了,这里Android中也是封装好了接口

我们可以通过void android.webkit.WebView.addJavascriptInterface(Object object, String name)的方法来实现服务器端调用我们的代码,其中这个方法有两个参数,一个是object,另一个是String类型的; 只要webview调用了这个方法就可以调用我们的代码了。而要调用的代码我们写在Object里面,首先我们就先实现这个Object,我们创建一个类,JavaScriptInterface。Android中APi Guides中提供的Demo中取得累的名字是JavaScriptInterface,那我们也用这个名字把。然后实现它,然后随便在里面写一个方法,如下面

JavaScriptInterface.Java类



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import java.util.HashMap;  
02.import java.util.Map;  
03.  
04.import android.content.Context;  
05.import android.os.Handler;  
06.import android.os.Message;  
07.import android.text.TextUtils;  
08.import android.util.Log;  
09.import android.webkit.JavascriptInterface;  
10.import android.widget.Toast;  
11.  
12./** 
13. *  
14. * Title: JavaScriptInterface.java Description: 
15. *  
16. * @author Liusong 
17. * @version V1.0 
18. */  
19.public class JavaScriptInterface {    
20.          
21.    /** Instantiate the interface and set the context */  
22.    public JavaScriptInterface() {  
23.    }  
24.  
25.    /** Show a toast from the web page */  
26.    @JavascriptInterface  
27.    public void showToast() {  
28.        Log.i("TAG", "调用成功==================》》》》》");  
29.  
30.    }  
31.  
32.}  





这样就完成了一个简单的JavaScriptInterface类,这个类的方法是自己随便写的,其中,先说一下这里要注意的几点,首先重要的@JavascriptInterface这个注解,你会发现去掉也不会报错,但是这个是很早重要的,如果你想让服务器端调用你的方法,你就要加上这个注解@JavascriptInterface。在4.4api中说道,一定要加这个注解,负责调用不会成功,其实我在开发中,用红米1s,4.3的系统,就没法调用成功了,当时还纳闷,因为当时手里的文档是4.2的,很是郁闷。所以在这里强掉,一定要在自己写的方法前面加上@JavascriptInterface。

还有一个注意的是方法的参数,这里是一个无参方法,当然这里你也可以写一个有参方法,这里先提一下,待会会配合html里面的js说道,我们先说void android.webkit.WebView.addJavascriptInterface(Object object, String name)这个方法里面的第二个参数,第二个参数你可以理解为是标识符,就是服务器端调用你方法时,需要找到你,怎么找到?就是通过这个标识符,标识符是自己随便定的,但是,你要告诉后台开发人员你的标识符是什么,我们这里把这第二个参数设置为“Android”。下面我给出我测试的html代码结合着看你就明白了。

test.html



[html] view plain copy print?在CODE上查看代码片派生到我的代码片
01.<!doctype html>  
02.<html>  
03.<head>  
04.    <meta name="viewport" content="width=device-width, initial-scale=1" charset="GBK">  
05.    <title>测试</title>  
06.</head>  
07.  
08.<body>  
09.  
10.<div data-role="page" >  
11.      
12.<script type="text/javascript">  
13.     function callAndroidAction(action) {  
14.        Android.showToast();        alert("我敢保证,你现在用的是演示一");  
15.    }  
16.     function forSmallPhoto(action) {  
17.        alert("我敢保证,你现在用的是演示一"+action);  
18.    }  
19.</script>  
20.  
21.    <div data-role="header">  
22.        <h1>调用图库</h1>  
23.        <!--   <a href="#" class="ui-btn">返回</a>-->  
24.    </div>  
25.  
26.    <div data-role="main" class="ui-content">  
27.  
28.        <div style="width: 98%;margin: 0 auto; text-align: center">  
29.            <a href="#" class=" ui-btn ui-btn-inline" onclick="callAndroidAction(0)">调用图库  </a>  
30.              
31.            <a href="#" class=" ui-btn ui-btn-inline" onclick="callAndroidAction('2')"> 充值  </a>  
32.          
33.        </div>  
34.  
35.  
36.    </div>  
37.  
38.     
39.</div>  
40.  
41.</body>  
42.  
43.  
44.</html>  





这个代码有点乱,就将就这看吧,我是把这个页面放在自己的tomcat上的,其中这个html中大家发现
 



[html] view plain copy print?在CODE上查看代码片派生到我的代码片
01.<script type="text/javascript">  
02.    function callAndroidAction(action) {  
03.        Android.showToast();  
04.        alert("我敢保证,你现在用的是演示一");  
05.    }  
06.   function forSmallPhoto(action) {  
07.        alert("我敢保证,你现在用的是演示一"+action);  
08.    }  
09.</script>  





  

这个js方法没,看见里面的Android标识符没,没错,后台就是这么调用我们代码的,Android.showToast();就是这么调用的,就是这么简单,不要想的太难,我们就需按我上面说的那样,把Object实现,把标识符写好就ok了。饭后,后台就会通过标识符和你Object的方法名字调用你的方法。这里要说一下,你Object(即JavaScriptInterface,我们上面已经实现)里的方法的参数要和后台调用你的方法的参数个数和类型一直,就像我们平时调用方法是一样的。这一点知道了就好了。

这样就可以了。

所以WebViewActivity里面加上这一句就可以了。



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.view.addJavascriptInterface(new JavaScriptInterface(),"Android");  




 

这样js就说完了。

模版

当后台要调用我们的代码,我们就写一个方法,如果调用多次我们就写多个,这样太麻烦,所以我们来写一个通用的方法,就是无论后台调用你代码干不同的事,都调用你这个方法,那怎么区分不同的执行动作呢?用传的参数,我们在JavaScriptInterface里面写一个方法,这里就叫callAndroidAction,我设计的是给这个方法三个参数,

public void callAndroidAction(String action, String url,String json),*个参数action,即用来表示要执行的动作,第二个则是url,不管是服务其给的下载路径还是,访问其他页面的路径,在一个json就是其他一些参数,由于传的参数不固定,我们就用一个参数,一个参数时就传过来,多个参数时可以通过json字符串传过来,就没必要麻烦一个一个的写参数了。

然后我们在设计一个回调,让操作的代码拿出去,怎大体就是这样了



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import java.util.HashMap;  
02.import java.util.Map;  
03.  
04.import android.content.Context;  
05.import android.os.Handler;  
06.import android.os.Message;  
07.import android.text.TextUtils;  
08.import android.util.Log;  
09.import android.webkit.JavascriptInterface;  
10.import android.widget.Toast;  
11.  
12./** 
13. *  
14. * Title: JavaScriptInterface.java Description: 
15. *  
16. * @author Liusong 
17. * @version V1.0 
18. */  
19.public class JavaScriptInterface {  
20.      
21.    private Handler mHandler;  
22.      
23.    /** Instantiate the interface and set the context */  
24.    public JavaScriptInterface(Handler handler) {  
25.        mHandler = handler;  
26.    }  
27.  
28.    /** Show a toast from the web page */  
29.    @JavascriptInterface  
30.    public void showToast(final String toast) {  
31.        Log.i("TAG", "调用成功==================》》》》》");  
32.    }  
33.  
34.    @JavascriptInterface  
35.    public void callAndroidAction(String action, String url,String json) {  
36.        Map<String, String> params = new HashMap<String, String>();  
37.        if(!TextUtils.isEmpty(url)){  
38.            params.put("url", url);  
39.        }  
40.        if(!TextUtils.isEmpty(json)){  
41.            params.put("json", json);  
42.        }  
43.        Message msg = Message.obtain();  
44.        msg.what = Integer.valueOf(action);  
45.        msg.obj = params;  
46.        mHandler.sendMessage(msg);  
47.    }  
48.}  





这样我们就从服务其拿到的参数都给Handler了,则WebViewActivity里面就要这样写了



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.import java.util.HashMap;  
02.import java.util.Map;  
03.  
04.import android.app.Activity;  
05.import android.os.Bundle;  
06.import android.os.Handler;  
07.import android.os.Message;  
08.import android.webkit.WebSettings;  
09.import android.webkit.WebView;  
10.  
11.public class WebViewActivity extends Activity {  
12.    private static final String url = "http://192.168.30.199:8080/song/test.html";  
13.      
14.    //执行动作  
15.    public static final int SELECT_IMAGE = 0;// 打开图库  
16.    public static final int OPEN_PAGE = 1;// 跳转其他特定页面  
17.    public static final int CLOSE_OR_BACK = 2;// 关闭或  
18.      
19.    private WebView mWebView;  
20.    @Override  
21.    protected void onCreate(Bundle savedInstanceState) {  
22.        super.onCreate(savedInstanceState);  
23.        setContentView(R.layout.activity_webviw);  
24.        initView();  
25.    }  
26.   <p>  
27.     private void getIntentDatas() {  
28.          // TODO Auto-generated method stub  
29.        url = getIntent().getStringExtra("url");  
30.   }</p><p> </p>    private void initView() {  
31.        mWebView = (WebView) findViewById(R.id.webview);  
32.        //或的WebView的Setting  
33.        WebSettings settings = mWebView.getSettings();  
34.        //设置支持js,看方法名字就知道啥意思  
35.        settings.setJavaScriptEnabled(true);  
36.        mWebView.addJavascriptInterface(new JavaScriptInterface(handler), "Android");  
37.        //加载网页路径  
38.        mWebView.loadUrl(url);  
39.    }  
40.      
41.    private Handler handler = new Handler(){  
42.        public void handleMessage(Message msg) {  
43.            switch (msg.what) {  
44.            case SELECT_IMAGE://执行打开图库,  
45.                  
46.                //如果有参数,取服务端传过来的参数(url,json)  
47.                Map<String, String> params = (HashMap<String, String>)msg.obj;  
48.                break;  
49.                  
50.            //其他功能,可随着自己功能的增加,在这里增加,只需和后台商量好动作的action值即可  
51.            default:  
52.                break;  
53.            }  
54.        };  
55.    };  
56.}  




*后再让WebViewActivity通用,就是通过传url参数



[java] view plain copy print?在CODE上查看代码片派生到我的代码片
01.private void getIntentDatas() {  
02. // TODO Auto-generated method stub  
03. url = getIntent().getStringExtra("url");  
04.}
复制代码
复制代码

安卓该如何显示 slatejs 格式的数据?

安卓该如何显示 slatejs 格式的数据?

 

pigspy · 2 天前 · 619 次点击

服务器接口返回的数据是 slatejs 的数据格式,类似

[{
	"type": "paragraph",
	"children": [{
		"type": "emotion",
		"id": 51,
		"children": [{
			"text": ""
		}]
	}, {
		"text": "来去也就剩下那么些人了。"
	}]
}]

安卓 APP 应该怎么显示呢?不想用 webview 来处理

12 条回复    2021-08-19 20:55:42 +08:00

learningman
    1

learningman   2 天前

这不 json 吗
pigspy
    2

pigspy   2 天前

@learningman

slatejs 是一个 web 端的富文本框架,这个数据结构翻译成 html 就是 `<p><img src=”./51″>来去也就剩下那么些人了。<p>`,
麻烦一点的办法就是要手写一个解析器,把 slatejs 的数据格式先转换为 html,然后再用安卓的 HTML 工具类来转换为 TextView 可以显示的数据结构
我想问问有没有办法直接在安卓端显示这种数据

wobuhuicode
    3

wobuhuicode   2 天前

这种*简单的方法就是直接用 webview 。使用 js 来解析 js 。*后导出回去给 java
pigspy
    4

pigspy   2 天前

@wobuhuicode
webview 估计是*后的备选方案,因为这是个发帖回帖的界面,原来整个模块都是 kotlin 写的,如果要换成 webview 的话,工作量太大了
wobuhuicode
    5

wobuhuicode   2 天前

@pigspy webview 只是用来解析,不要求它用来展示。解析完了数据返回 kotlin 层,销毁 webview
tanranran
    6

tanranran   2 天前

@pigspy #4 webview 和 kotlin 是两回事吧,建议 webview,自己写解析器的话,要考虑的问题太多了
zhanlanhuizhang
    7

zhanlanhuizhang   2 天前

等的就是这个时候,天降大任,你实现一个轮子。
ZoteTheMighty
    8

ZoteTheMighty   2 天前

直接 new 一个 webview 解析,这个 WebView 不需要展示, 只需要在 WebView 的 onLoadResource (好像是这个)里去拿解析的东西就好了, 然后退出销毁该 WebView 即可。
pigspy
    9

pigspy   1 天前 via Android

@wobuhuicode
明白你的意思了,非常感谢
ch2
    10

ch2   1 天前

这种是富文本,你写个 converter 转成安卓原生富文本元素就行了

aristolochic
    11

aristolochic   1 天前

Slate 的官方序列化示例就是 switch 判断 children.type 对应输出 html 片段+递归;期间只用到了 Text 类作为判断是否为文本节点结束递归的依据。
所以其实对着它的 spec 很快就能写出来,也不必要用它的 Text 类判断是否为文本,文本节点特征很明显嘛。
如果 case 不多的话,为了这个需求就启动一个 WebView 是不是有些 Overkill 了
pigspy
    12

pigspy   1 天前

@aristolochic

嗯,我现在就是照着官网的例子自己写了一个反序列化函数来转换成 html

iOS获取webView的内容高度

– (void)webViewDidFinishLoad:(UIWebView *)webView

{
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@”document.body.offsetHeight”] floatValue];

CGRect frame = webView.frame;

webView.frame = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, height);

}

WebView加载网页不显示图片解决办法

对于大家来讲WebView肯定很熟悉,因为我们在日常开发中经常用到它。所以对于它的一些基本用法我就不在这啰嗦了,直接进入正题。

我遇到的问题就是在使用WebView加载网页的时候图片不显示(我手机系统是5.1.1),当时出现这个问题我就想当然的以为,是不是给WebView少设置的什么东西。然后百度一下:
mWebview.getSettings().setJavaScriptEnabled(true);//启用js
mWebview.getSettings().setBlockNetworkImage(false);//解决图片不显示

然后我检查了自己代码,这两句话也明明加了啊,这到底是什么鬼。后面我也加过其它的一些设置,依然没有用。难道是我的访问路径有问题吗,于是我随便找了带图片的网页,使用WebView加载了一下,哎呦我擦,图片显示没毛病啊。看来还真是我的访问路径有问题啊,但是别的都显示没问题,为什么就图片不显示呢。我跟踪断点把访问的路径复制了出来一看,我靠原来访问路径是https的呀。于是我就把矛头指向了https,简单来说,https就是http的安全版,它在http的基础上加入了ssl层。https协议在使用的时候需要申请一个安全证书,我就想是不是安全证书有问题,回头一想假如安全证书有问题,页面应该是直接显示空白才对。问题又出在哪,于是我把网页路径复制到了浏览器打开,然后查看了一下网页源码,发现图片的引用是http的,问题会不会就出在这呢。果然不出所料:


if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP) settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);


于是在设置WebView的时候加上了这句话,果然问题解决了。在5.0以下的系统即使不加这句话,图片也可以正常显示,亲测有效。

Android WebView填坑记录

前言

在应用程序开发过程中,经常会采用webview来展现某些界面,这样就可以不受发布版本控制,实时更新,遇到问题可以快速修复。

但是在Android开发中,由于Android版本分化严重,每一个版本针对webview都有部分更改,因此在开发过程中会遇到各种各样的坑,因此在此总结一下在开发过程中遇到的一些坑!

样例

这里不是讲解怎么进行webview开发,而是只罗列其中遇到的一些坑!为了展示这些问题,我们还是写一个样例来进行展开。

样例代码:

  1. /**
  2. * WebView demo
  3. */
  4. public class WebViewActivity extends AppCompatActivity {
  5. public static void start(Context context) {
  6. Intent intent = new Intent();
  7. intent.setClass(context, WebViewActivity.class);
  8. context.startActivity(intent);
  9. }
  10. private static final String TAG = “WebViewActivity”;
  11. public static final String URL = “http://www.163.com”;
  12. private static final int REQUEST_CODE_GET_LOCAL_FILE = 0;
  13. private static final int REQUEST_CODE_GET_LOCAL_FILE_NEW = 1;
  14. private WebView webView;
  15. @Override
  16. protected void onCreate(Bundle savedInstanceState) {
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.activity_web_view);
  19. findViews();
  20. initWebView();
  21. }
  22. /**
  23. * 查找界面view
  24. */
  25. private void findViews() {
  26. webView = (WebView) findViewById(R.id.web_view);
  27. }
  28. /**
  29. * 初始化webview参数
  30. */
  31. private void initWebView() {
  32. initWebSetting();
  33. setAcceptThirdPartyCookies();
  34. initWebClient();
  35. loadUrl();
  36. }
  37. /**
  38. * 加载地址
  39. */
  40. private void loadUrl() {
  41. webView.loadUrl(URL);
  42. }
  43. /**
  44. * 设置WebSetting
  45. */
  46. private void initWebSetting() {
  47. WebSettings webSettings = webView.getSettings();
  48. webSettings.setJavaScriptEnabled(true);
  49. webSettings.setDomStorageEnabled(true);
  50. webSettings.setLoadWithOverviewMode(true);
  51. webSettings.setUseWideViewPort(true);
  52. webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);
  53. webSettings.setUserAgentString(webSettings.getUserAgentString() + ” VersionCode/” + InstallUtil
  54. .getVersionCode(this));
  55. webSettings.setAppCacheMaxSize(1024 * 1024 * 8);
  56. webSettings.setAllowFileAccess(true);
  57. webSettings.setAppCacheEnabled(true);
  58. webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
  59. webSettings.setSupportZoom(true);
  60. webSettings.setGeolocationEnabled(true);
  61. webSettings.setDatabaseEnabled(true);
  62. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  63. webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
  64. }
  65. }
  66. /**
  67. * 设置跨域cookie读取
  68. */
  69. public final void setAcceptThirdPartyCookies() {
  70. //target 23 default false, so manual set true
  71. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  72. CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
  73. }
  74. }
  75. /**
  76. * 设置client
  77. */
  78. private void initWebClient() {
  79. webView.setWebChromeClient(new WebChromeClient() {
  80. @Override
  81. public void onProgressChanged(WebView view, int newProgress) {
  82. super.onProgressChanged(view, newProgress);
  83. Log.e(TAG, “onProgressChanged newProgress=” + newProgress);
  84. }
  85. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  86. @Override
  87. public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
  88. FileChooserParams fileChooserParams) {
  89. uploadFileNew = filePathCallback;
  90. Intent intent = fileChooserParams.createIntent();
  91. try {
  92. startActivityForResult(intent, REQUEST_CODE_GET_LOCAL_FILE_NEW);
  93. } catch (Exception e) {
  94. ToastUtil.showLong(getString(R.string.choose_fail));
  95. return false;
  96. }
  97. return true;
  98. }
  99. //
  100. // FILE UPLOAD <3.0
  101. //
  102. public void openFileChooser(ValueCallback<Uri> uploadFile) {
  103. chooseFile(uploadFile, null, null);
  104. }
  105. public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) {
  106. chooseFile(uploadFile, acceptType, null);
  107. }
  108. /**
  109. * 4.x
  110. * @param uploadFile
  111. * @param acceptType
  112. * @param capture
  113. */
  114. public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
  115. chooseFile(uploadFile, acceptType, capture);
  116. }
  117. });
  118. webView.setWebViewClient(new WebViewClient() {
  119. @Override
  120. public void onPageStarted(WebView view, String url, Bitmap favicon) {
  121. super.onPageStarted(view, url, favicon);
  122. Log.e(TAG, “onPageStarted”);
  123. }
  124. @Override
  125. public void onPageFinished(WebView view, String url) {
  126. super.onPageFinished(view, url);
  127. Log.e(TAG, “onPageFinished”);
  128. }
  129. @Override
  130. public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
  131. super.onReceivedError(view, request, error);
  132. Log.e(TAG, “onReceivedError”);
  133. }
  134. @Override
  135. public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
  136. super.onReceivedSslError(view, handler, error);
  137. Log.e(TAG, “onReceivedSslError”);
  138. }
  139. @Override
  140. public boolean shouldOverrideUrlLoading(WebView view, String url) {
  141. Log.e(TAG, “shouldOverrideUrlLoading url=” + url);
  142. return super.shouldOverrideUrlLoading(view, url);
  143. }
  144. });
  145. }
  146. private ValueCallback<Uri[]> uploadFileNew;
  147. private ValueCallback<Uri> uploadFile;
  148. /**
  149. * 文件选择
  150. *
  151. * @param uploadFile
  152. * @param acceptType
  153. * @param capture
  154. */
  155. private void chooseFile(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
  156. Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
  157. if (TextUtils.isEmpty(acceptType)) {
  158. acceptType = “*/*”;
  159. }
  160. intent.setType(acceptType);
  161. this.uploadFile = uploadFile;
  162. try {
  163. startActivityForResult(Intent.createChooser(intent, capture), REQUEST_CODE_GET_LOCAL_FILE);
  164. } catch (Throwable tr) {
  165. tr.printStackTrace();
  166. }
  167. }
  168. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  169. @Override
  170. public void onActivityResult(int requestCode, int resultCode, Intent data) {
  171. super.onActivityResult(requestCode, resultCode, data);
  172. switch (requestCode) {
  173. case REQUEST_CODE_GET_LOCAL_FILE:
  174. if (uploadFile != null) {
  175. uploadFile.onReceiveValue((resultCode == Activity.RESULT_OK && data != null) ? data.getData() :
  176. null);
  177. uploadFile = null;
  178. }
  179. break;
  180. case REQUEST_CODE_GET_LOCAL_FILE_NEW:
  181. if (uploadFileNew != null) {
  182. uploadFileNew.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
  183. uploadFileNew = null;
  184. }
  185. break;
  186. }
  187. }
  188. }

 

 

布局代码

  1. <?xml version=”1.0″ encoding=”utf-8″?>
  2. <RelativeLayout
  3. xmlns:android=“http://schemas.android.com/apk/res/android”
  4. xmlns:tools=“http://schemas.android.com/tools”
  5. android:layout_width=“match_parent”
  6. android:layout_height=“match_parent”
  7. tools:context=“com.sunny.demo.webview.WebViewActivity”>
  8. <WebView
  9. android:id=“@+id/web_view”
  10. android:layout_width=“match_parent”
  11. android:layout_height=“match_parent”>
  12. </WebView>
  13. </RelativeLayout>

 

填坑

1,回调不成对

在WebView加载地址时,在加载过程中回调次数不一定相同,比如这里我们我们加载http://www.163.com。

  1. E/WebViewActivity: onProgressChanged newProgress=10
  2. E/WebViewActivity: onPageStarted
  3. E/WebViewActivity: shouldOverrideUrlLoading url=http://3g.163.com/
  4. E/WebViewActivity: onPageStarted
  5. E/WebViewActivity: onPageStarted
  6. E/WebViewActivity: shouldOverrideUrlLoading url=http://3g.163.com/touch/
  7. E/WebViewActivity: onProgressChanged newProgress=50
  8. E/WebViewActivity: onPageFinished
  9. E/WebViewActivity: onProgressChanged newProgress=52
  10. E/WebViewActivity: onProgressChanged newProgress=90
  11. E/WebViewActivity: onProgressChanged newProgress=95
  12. E/WebViewActivity: onProgressChanged newProgress=100
  13. E/WebViewActivity: onPageFinished

 

从上面的日志中可以看到onPageStarted与onPageFinished次数不一致,因此如果你在start中进行进度条加载处理,finish中结束,会导致进度条一直不消失。因此可以在onProgressChanged进行处理。当newProgress为100时表示页面加载完成。

2,文件选择回调函数更改

如果你是web页面开发人员,如果要选取本地文件,可以采用input标签,如下一个简单的html页面:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4. <meta charset=“UTF-8”>
  5. <title>Document</title>
  6. </head>
  7. <body>
  8. <input type=“file” accept=“image/*;” capture=“camera” >
  9. <a href=“test1.html”>url替换为test1页面</a>
  10. <script>
  11. var a = function() {
  12. //alert(1);
  13. };
  14. document.addEventListener(‘JSBridgeReady’,a);
  15. </script>
  16. </body>
  17. </html>

 

附录
如果你不是专业的web开发人员,但是又想进行web页面调试,可以自己搭建一个web服务,如果你采用的是MAC可以采用如下方案进行web服务搭建

1.用node装一个http-server

2.brew install node

3.npm install -g http-server 安装

4.在一个目录下 http-server启动就是一个简单http服务里 port 8080

上面的代码加载后效果如下:
这里写图片描述

很简单吧!是不是想说so easy!!!那我们就点击一下选择文件吧!

咦没效果
换手机,好,有效果
再换,咦,又没有效果

是不是感觉很抓狂?这是由于Android的不同版本,WebView的回调函数都不一致。怎么解决这个问题?可以复写不同的回调函数,这里主要有以下四个回调函数,分别处理不同的版本:

  1. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  2. @Override
  3. public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
  4. FileChooserParams fileChooserParams) {
  5. Intent intent = fileChooserParams.createIntent();
  6. try {
  7. startActivityForResult(intent, REQUEST_CODE_GET_LOCAL_FILE_NEW);
  8. } catch (Exception e) {
  9. ToastUtil.showLong(getString(R.string.choose_fail));
  10. return false;
  11. }
  12. return true;
  13. }
  14. //
  15. // FILE UPLOAD <3.0
  16. //
  17. public void openFileChooser(ValueCallback<Uri> uploadFile) {
  18. chooseFile(uploadFile, null, null);
  19. }
  20. public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) {
  21. chooseFile(uploadFile, acceptType, null);
  22. }
  23. /**
  24. * 4.x
  25. * @param uploadFile
  26. * @param acceptType
  27. * @param capture
  28. */
  29. public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
  30. chooseFile(uploadFile, acceptType, capture);
  31. }

 

复写了上述四个函数,同时记得onActivityResult进行返回结果处理。就算是这样,我也不敢保证所有的手机都能正确的进行处理。
刚才在html中是否看到了一个一段document.addEventListener(‘JSBridgeReady’,a)这样的代码。这里是想说给出另外一种解决方案,可以采用JSBridge方式进行web页面与native页面交互,这样就可以屏蔽版本中间的差异。

3,跨域cookie读取

什么是跨域,简单的说就是不同的域名,我们都知道在pc上我们用浏览器访问网址,不同的网址都会在本地存储一些cookie信息,这样就可以实现比如自动登录等功能,在pc上不同域名是不能相互读取其他域下的cookie信息的(非web专业开发人员,如果理解有误,欢迎指出)。

但是在Android上在api 23之前,是可以跨域读取cookie的,比如A域写入一个userId的cookie,B域可以读取该值。但是在23时,系统将该值设置成了false,不再让跨域读取了。如果你的应用有跨域读取需求,怎么办?可以采用如下方式进行开启:

  1. /**
  2. * 设置跨域cookie读取
  3. */
  4. public final void setAcceptThirdPartyCookies() {
  5. //target 23 default false, so manual set true
  6. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  7. CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
  8. }
  9. }

 

这里我们来看看setAcceptThirdPartyCookies的注释:

Sets whether the {@link WebView} should allow third party cookies to be set.
Allowing third party cookies is a per WebView policy and can be set
differently on different WebView instances.

Apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below
default to allowing third party cookies. Apps targeting
{@link android.os.Build.VERSION_CODES#LOLLIPOP} or later default to disallowing
third party cookies.

4,http/https混合加载

在现阶段,很多网站都改成了https进行访问,https可以提升访问网站的安全性,防止信息被窃取,如果所有的网页都是https且网页内的链接也是都是https,那就没有混合加载的问题了。但是很多资源现阶段还没有改变成https访问,往往页面都嵌入了http的链接。这种混合网页如果不进行处理,直接加载是会出现错误的。怎么解决这个问题?

  1. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  2. webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
  3. }

 

这也是一个分版本的函数,在api 23之前,默认是可以混合加载的,但是在23时,默认值改成了MIXED_CONTENT_NEVER_ALLOW,因此如果你有混合加载的需求,设置setMixedContentMode为MIXED_CONTENT_ALWAYS_ALLOW。

5,花屏

WebView如果开启了硬件加速,多次打开,会导致界面花屏,或者界面绘制有残留。这个在5.0刚出来的时候发生过多次,但是当时忘记截图了。当时也没有打算要把这些给记录下来。这里我已经复现不了了。如果你遇到了。关闭硬件加速就好了。

6,资源释放

这里我们先截取几张图来看看加载前与加载后webview内存的占用:
加载之前:
这里写图片描述
加载之后:
这里写图片描述
退出页面:
这里写图片描述

可以看到内存蹭蹭蹭的就上去了。就算退出去了也没有减少多少,因此这里必须手动进行资源释放,可以调用如下代码:

  1. @Override
  2. protected void onDestroy() {
  3. super.onDestroy();
  4. if (webView != null) {
  5. root.removeView(webView);
  6. webView.removeAllViews();
  7. webView.destroy();
  8. }
  9. }

 

也可以采用在界面中动态创建webview,之后add到页面中,甚至更有人会为该页面单独设置一个进程,之后退出后会调用exit函数进行资源释放。这里可以根据需求来进行设置。

总结

WebView有这样或者那样的坑。这里只是大致罗列自己遇到的一些,在知乎上也看到一个专门讲WebView坑的查看链接。大家可以去看看,有什么新的发现也可以进行探讨。

Android WebView学习资料

首先要在manifest.main文件中创建一个webview,然后再activity中定义这个webview然后
进行一下相关操作。

1、添加权限:AndroidManifest.xml中必须使用许可”android.permission.INTERNET”,否则会出
Web page not available错误。

2、在要Activity中生成一个WebView组件:WebView webView = new WebView(this);

3、设置WebView基本信息:

如果访问的页面中有Javascript,则webview必须设置支持Javascript。

webview.getSettings().setJavaScriptEnabled(true);

触摸焦点起作用

requestFocus();

取消滚动条

this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);

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

onLoadResource

onPageStart

onPageFinish

onReceiveError

onReceivedHttpAuthRequest

5、如果访问的页面中有Javascript,则webview必须设置支持Javascript ,否则显示空白页面。

Java代码

webview.getSettings().setJavaScriptEnabled(true);
6、如果页面中链接,如果希望点击链接继续在当前browser中响应,而不是新开Android的系统browser
中响应该链接,必须覆盖webview的WebViewClient对象:

Java代码

1. mWebView.setWebViewClient(new WebViewClient(){
2. public boolean shouldOverrideUrlLoading(WebView view, String url) {
3. view.loadUrl(url);
4. return true;
5. }
6. });

上述方法告诉系统由我这个WebViewClient处理这个Intent,我来加载URL。点击一个链接的Intent是向上
冒泡的,shouldOverrideUrlLoading方法return true表示我加载后这个Intent就消费了,不再向上冒泡了。
7、如果不做任何处理,在显示你的Brower UI时,点击系统“Back”键,整个Browser会作为一个整体“Back”

到其他Activity中,而不是希望的在Browser的历史页面中 Back。如果希望实现在历史页面中Back,需
要在当前Activity中处理并消费掉该Back事件:

Java代码

1. public boolean onKeyDown(int keyCode, KeyEvent event) {
2. if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
3. mWebView.goBack();
4. return true;
5. }
6. return super.onKeyDown(keyCode, event);
7. }

对于Android 2.0开始又多出了一种新的方法,对于Activity 可以单独获取Back键的按下事件,直接重
写 onBackPressed 方法即可,代码如下

Java代码

@Override
1、public void onBackPressed() {
2、 // 这里处理逻辑代码,该方法仅适用于2.0或更高版本的sdk
3、 return ;
4、}

 

这里还有几个知识点:

 

1)为了让WebView从apk文件中加载 assets,Android SDK提供了一个schema,前缀为
“file:///android_asset/”。WebView遇到这样的schema,就去当前包中的 assets目录中找内
容。如上面的”file:///android_asset/demo.html”

 

2)addJavascriptInterface方法中要绑定的 Java对象及方法要运行另外的线程中,不能运行在
构造他的线程中,这也是使用Handler的目的。

 

Webview的两种显示网页的方法:

(1):webview.loadUrl(“www.baidu.com”);

public class WebviewTest extends Activity {

/** Called when the activity is first created. */

 

private WebView mWebView;

private Button bt1;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

mWebView = (WebView)findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();

webSettings.setJavaScriptEnabled(true);

 

bt1 = (Button)findViewById(R.id.Button01);

 

bt1.setOnClickListener(new View.OnClickListener() {

 

 

public void onClick(View arg0) {

// TODO Auto-generated method stub

webview.loadUrl(“www.baidu.com”);

}

});

}

}

 

(2):自定义网页:Webview.data();

 

public class WebviewTest extends Activity {

/** Called when the activity is first created. */

 

private WebView mWebView;

private Button bt1;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

mWebView = (WebView)findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();

webSettings.setJavaScriptEnabled(true);

 

bt1 = (Button)findViewById(R.id.Button01);

 

bt1.setOnClickListener(new View.OnClickListener() {

 

 

public void onClick(View arg0) {

// TODO Auto-generated method stub

String str = “asdas”;

mWebView.loadData(

“<html><body>”+str+”</body></html>”,

“text/html”, “utf-8″);

}

});

}

}

 

Webview的常用方法实例:

 

Manifest.xml中的代码:

加入权限:

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

布局文件中的代码:

<?xml version=”1.0″ encoding=”utf-8″?>

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”

android:orientation=”vertical” android:layout_width=”fill_parent”

android:layout_height=”fill_parent”>

<WebView android:id=”@+id/WebView01″ android:layout_width=”fill_parent”

android:layout_height=”fill_parent”></WebView>

</LinearLayout>

 

TestWebviewDemo中的代码:

public class TestWebviewDemo extends Activity {

/** Called when the activity is first created. */

private static final String TAG = “TestWebviewDemo”;

private WebView mWebView;

private Handler mHandler = new Handler();

private int mDensity;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

 

mWebView = (WebView) findViewById(R.id.WebView01);

mWebView.getSettings().setAllowFileAccess(true);// 设置允许访问文件数据

mWebView.getSettings().setBuiltInZoomControls(true);// 设置支持缩放

mWebView.getSettings().setSavePassword(false); // 设置是否保存密码

// 设置支持JavaScript脚本

mWebView.getSettings().setJavaScriptEnabled(true);

// 设置支持各种不同的设备

mWebView

.getSettings()

.setUserAgentString(

“Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us)
AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10”);

// 通过这个设置来执行加载webview网页时所要执行的一些方法

mWebView.setWebViewClient(new WebViewClient() {

// 新开页面时用自己定义的webview来显示,不用系统自带的浏览器来显示

public boolean shouldOverrideUrlLoading(WebView view, String url) {

// TODO Auto-generated method stub

// 当有新连接时使用当前的webview进行显示

view.loadUrl(url);

return super.shouldOverrideUrlLoading(view, url);

}

// 开始加载网页时要做的工作

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

 

super.onPageStarted(view, url, favicon);

}

//加载完成时要做的工作

public void onPageFinished(WebView view, String url) {

 

super.onPageFinished(view, url);

}

// 加载错误时要做的工作

public void onReceivedError(WebView view, int errorCode,

String description, String failingUrl) {

Log.d(TAG, “error=” + description);

Toast.makeText(TestWebviewDemo.this,

errorCode + “/” + description, Toast.LENGTH_LONG)

.show();

}

});

// 处理网页中的一些对话框信息(提示对话框,带选择的对话框,带输入的对话
框)

mWebView.setWebChromeClient(new WebChromeClient() {

// 对话框

public boolean onJsAlert(WebView view, String url, String message,

final JsResult result) {

// 构建一个Builder来显示网页中的alert对话框

Builder builder = new Builder(TestWebviewDemo.this);

builder.setTitle(“提示对话框”);

builder.setMessage(message);

builder.setPositiveButton(android.R.string.ok,

new AlertDialog.OnClickListener() {

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.confirm();

}

});

builder.setCancelable(false);

builder.create();

builder.show();

return true;

}

// 带按钮的对话框

public boolean onJsConfirm(WebView view, String url,

String message, final JsResult result) {

Builder builder = new Builder(TestWebviewDemo.this);

builder.setTitle(“带选择的对话框”);

builder.setMessage(message);

builder.setPositiveButton(android.R.string.ok,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.confirm();

}

 

});

builder.setNeutralButton(android.R.string.cancel,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.cancel();

}

 

});

builder.setCancelable(false);

builder.create();

builder.show();

return true;

}

// 带输入框的对话框

public boolean onJsPrompt(WebView view, String url, String message,

String defaultValue, final JsPromptResult result) {

LayoutInflater inflater = LayoutInflater

.from(TestWebviewDemo.this);

final View v = inflater.inflate(R.layout.prom_dialog, null);

// 设置 TextView对应网页中的提示信息

((TextView) v.findViewById(R.id.TextView_PROM))

.setText(message);

// 设置EditText对应网页中的输入框

((EditText) v.findViewById(R.id.EditText_PROM))

.setText(defaultValue);

Builder builder = new Builder(TestWebviewDemo.this);

builder.setTitle(“带输入的对话框”);

builder.setView(v);

builder.setPositiveButton(android.R.string.ok,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

String value = ((EditText) v

.findViewById(R.id.EditText_PROM))

.getText().toString();

result.confirm(value);

}

});

builder.setNegativeButton(android.R.string.cancel,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.cancel();

}

});

builder

.setOnCancelListener(new DialogInterface.OnCancelListener() {

 

@Override

public void onCancel(DialogInterface dialog) {

// TODO Auto-generated method stub

result.cancel();

}

 

});

builder.create();

builder.show();

return true;

 

}

 

// 设置网页加载的进度条

public void onProgressChanged(WebView view, int newProgress) {

TestWebviewDemo.this.getWindow().setFeatureInt(

Window.FEATURE_PROGRESS, newProgress * 100);

super.onProgressChanged(view, newProgress);

}

 

// 设置应用程序的标题

public void onReceivedTitle(WebView view, String title) {

TestWebviewDemo.this.setTitle(title);

super.onReceivedTitle(view, title);

}

 

});

// 与网页进行交互的addJavascriptInterface()的方法

mWebView.addJavascriptInterface(new Object() {

public void clickOnAndroid(final String str) {

mHandler.post(new Runnable() {

@Override

public void run() {

// 逻辑代码

});

}

}, “demo”);

 

if (mDensity == 240) { // 可以让不同的density的情况下,可以让页面进行适配

mWebView.getSettings().setDefaultZoom(ZoomDensity.FAR);

} else if (mDensity == 160) {

mWebView.getSettings().setDefaultZoom(ZoomDensity.MEDIUM);

} else {

mWebView.getSettings().setDefaultZoom(ZoomDensity.CLOSE);

}

String strUrl = “http://10.0.2.2:8080/WebTest3″;

mWebView.loadUrl(strUrl);

}

//处理返回的事件,(后退进入前一个界面而不是全部退出)

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {

mWebView.goBack();// 返回前一个页面

return true;

}

return super.onKeyDown(keyCode, event);

}

 

 

 

 

Webview中java与网页进行数据交互:

先看我们的html文档:

<html>

<script language=”javascript”>

/* This function is invoked by the activity */

function wave() {

alert(“1”);

document.getElementById(“droid”).src=”android_waving.png”;

alert(“2″);

}

</script>

<body>

<!– Calls into the javascript interface for the activity –>

//js调用Java方法

<a onClick=”window.demo.clickOnAndroid()”><div style=”width:80px;

margin:0px auto;

padding:10px;

text-align:center;

border:2px solid #202020;” >

<img id=”droid” src=”android_normal.png”/><br>

Click me!

</div></a>

</body>

</html>

 

Manifest.Xml中:

加入权限:

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

 

再看我们的java 代码。

Java代码

public class WebViewDemo extends Activity {

 

private static final String LOG_TAG = “WebViewDemo”;

 

private WebView mWebView;

 

private Handler mHandler = new Handler();

 

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

mWebView = (WebView) findViewById(R.id.webview);

 

WebSettings webSettings = mWebView.getSettings();

webSettings.setSavePassword(false);

webSettings.setSaveFormData(false);

webSettings.setJavaScriptEnabled(true);

webSettings.setSupportZoom(false);

 

mWebView.setWebChromeClient(new MyWebChromeClient());

//自定义的Demo,供js网页调用

mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), “demo”);

 

mWebView.loadUrl(“file:///android_asset/demo.html”);

}

final class DemoJavaScriptInterface {

 

DemoJavaScriptInterface() {

}

 

/**

* This is not called on the UI thread. Post a runnable to invoke

* loadUrl on the UI thread.

*/

public void clickOnAndroid() {

//用handler来更新UI

mHandler.post(new Runnable() {

public void run() {

//Java调用js方法

mWebView.loadUrl(“javascript:wave()”);

}

});

}

}

/**

* Provides a hook for calling “alert” from javascript. Useful for

* debugging your javascript.

*/

final class MyWebChromeClient extends WebChromeClient {

@Override

public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

Log.d(LOG_TAG, message);

result.confirm();

return true;

}

 

}

}

 

 

再看个例子:

Html中的代码:

<script type=”text/JavaScript”>

function s(){

alert(“Good Morning!”);

}

function d(){

confirm(“Are you ok?”)

}

function f(){

prompt(“What’s your name?”)

}

</script>

</head>

 

<body>

<body>

下面我们演示三种对话框

<br/><br/>

<input type=”button” value=”警告,提醒对话框” οnclick=”s()”>

<br/><br/>

<input type=”button” value=”带选择的对话框” οnclick=”d()”>

<br/><br/>

<input type=”button” value=”要求用户输入的对话框” οnclick=”f()”>

</body>

 

Manifest.Xml中:

加入权限:

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

 

Java中的代码:

public class Test extends Activity {

/** Called when the activity is first created. */

private EditText et = null;

private Button btn = null;

private WebView wv = null;

private WebSettings ws = null;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

et = (EditText) this.findViewById(R.id.EditText01);

btn = (Button) this.findViewById(R.id.Button01);

wv = (WebView) this.findViewById(R.id.WebView);

ws = wv.getSettings();

ws.setAllowFileAccess(true);//设置允许访问文件数据

ws.setJavaScriptEnabled(true);//设置支持javascript脚本

ws.setBuiltInZoomControls(true);//设置支持缩放

wv.requestFocus();

wv.setWebViewClient(new WebViewClient(){

public boolean shouldOverrideUrlLoading(WebView view,String url){

//当有新连接时,使用当前的 WebView

view.loadUrl(url);

return true;

}

});

wv.setWebChromeClient(new WebChromeClient(){

public boolean onJsAlert(WebView view,String url,String message,final JsResult
result){

//构建一个Builder来显示网页中的alert对话框

Builder builder = new Builder(Test.this);

builder.setTitle(“提示对话框”);

builder.setMessage(message);

builder.setPositiveButton(android.R.string.ok, new
AlertDialog.OnClickListener(){

 

 

@Override

public void onClick(DialogInterface dialog, int which) {

// TODO Auto-generated method stub

result.confirm();

}

 

});

builder.setCancelable(false);

builder.create();

builder.show();

return true;

}

public boolean onJsConfirm(WebView view,String url,String message,final
JsResult result){

Builder builder = new Builder(Test.this);

builder.setTitle(“带选择的对话框”);

builder.setMessage(message);

builder.setPositiveButton(android.R.string.ok, new
AlertDialog.OnClickListener(){

 

@Override

public void onClick(DialogInterface dialog, int which) {

// TODO Auto-generated method stub

result.confirm();

}

 

});

builder.setNeutralButton(android.R.string.cancel, new
AlertDialog.OnClickListener(){

 

@Override

public void onClick(DialogInterface dialog, int which) {

// TODO Auto-generated method stub

result.cancel();

}

 

});

builder.setCancelable(false);

builder.create();

builder.show();

return true;

}

public boolean onJsPrompt(WebView view,String url,String message,String
defaultValue,final JsPromptResult result){

LayoutInflater inflater = LayoutInflater.from(Test.this);

final View v = inflater.inflate(R.layout.prom_dialog, null);

//设置 TextView对应网页中的提示信息

((TextView)v.findViewById(R.id.TextView_PROM)).setText(message);

//设置EditText对应网页中的输入框

((EditText)v.findViewById(R.id.EditText_PROM)).setText(defaultValue);

Builder builder = new Builder(Test.this);

builder.setTitle(“带输入的对话框 “);

builder.setView(v);

builder.setPositiveButton(android.R.string.ok, new

AlertDialog.OnClickListener(){

 

@Override

public void onClick(DialogInterface dialog, int which) {

// TODO Auto-generated method stub

String value =
((EditText)v.findViewById(R.id.EditText_PROM)).getText().toString();

result.confirm(value);

}

 

});

builder.setNegativeButton(android.R.string.cancel, new
AlertDialog.OnClickListener(){

 

@Override

public void onClick(DialogInterface dialog, int which) {

// TODO Auto-generated method stub

result.cancel();

}

 

});

builder.setOnCancelListener(new DialogInterface.OnCancelListener(){

 

@Override

public void onCancel(DialogInterface dialog) {

// TODO Auto-generated method stub

result.cancel();

}

 

});

builder.create();

builder.show();

return true;

}

//设置网页加载的进度条

public void onProgressChanged(WebView view,int newProgress){

Test.this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
newProgress*100);

super.onProgressChanged(view, newProgress);

}

//设置应用程序的标题

public void onReceivedTitle(WebView view,String title){

Test.this.setTitle(title);

super.onReceivedTitle(view, title);

}

});

btn.setOnClickListener(new Button.OnClickListener(){

 

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

String url =et.getText().toString();

// String url = “http://10.0.2.2:8080/WebTest3”;

//判断输入的内容是不是网址

if(URLUtil.isNetworkUrl(url)){

Log.d(“++++++++++++”, “sadas”);

wv.loadUrl(url);

Toast.makeText(Test.this, url, Toast.LENGTH_SHORT).show();

}else{

et.setHint(“输入的网址不合法,请重新输入”);

// et.setText(“输入的网址不合法,请重新输入”);

}

}

 

});

}

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

if(keyCode==KeyEvent.KEYCODE_BACK && wv.canGoBack()){

wv.goBack();//返回前一个页面

return true;

}

return super.onKeyDown(keyCode, event);

}

 

}

 

 

 

需要注意的地方,很多数据类型js中不认识,*好是在android那边封装好,提供必要的方
法接口。比如传到js中的list,在js中是没办法去得到里面的元素的。

 

Manifest.Xml中:

加入权限:

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

 

html的带码

<script language=”javascript”>

window.οnlοad= function(){

var i=window.javatojs.getSize();

for(var n=0;n<i;n++){

var jsdata= window.javatojs.getObject(n);//拿到activity里面的属性javadata

var datalistdiv = document.getElementById(“datalist”); //得到页面的div

pnode = document.createElement(“p”);//创建一个p标签,再建个textnode

tnode = document.createTextNode(jsdata);

pnode.appendChild(tnode);//p中加入数据

datalistdiv.appendChild(pnode);//div中键入新的p

}

}

</script>

<body>

<div id = “datalist”>

 

this is a demo

</body>

 

Java的代码:

public class JavaToWebview extends Activity {

 

private WebView web;

public List list;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

initData();

setContentView(R.layout.webview);

web = (WebView)this.findViewById(R.id.webview);

web.getSettings().setJavaScriptEnabled(true);//开启javascript设置

web.addJavascriptInterface(this, “javatojs”);//把RIAExample的一个实例添加到js的全
局对象window中, //这样就可以使用window.javatojs来调用它的方法

web.loadUrl(“file:///android_asset/demo5.html”);//加载网页

 

}

void initData(){

list=new ArrayList<String>();

for(int i=0;i<5;i++){

list.add(“我是从数据库中读取的哈哈”);

}

}

/**

* 该方法将在js脚本中,通过window.javatojs…..()进行调用

* @return

*/

public Object getObject(int index){

return list.get(index);

}

public int getSize(){

return list.size();

}

}

 

再看一个查地图的例子:

Manifest.Xml中:

加入权限:

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

布局文件中的代码:

<?xml version=”1.0″ encoding=”utf-8″?>

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”

android:orientation=”vertical”

android:layout_width=”fill_parent”

android:layout_height=”fill_parent”

>

<TextView

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:text=”Welcome to Mr Wei’s Blog.”

/>

<WebView

android:id=”@+id/webview”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

/>

<Button

android:id=”@+id/button”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:text=”Change the webview content”

/>

</LinearLayout>

在assets目录下新建一个demo.html文件,代码如下:

<html>

<script language=”javascript”><!–

 

function fillContent(){

document.getElementById(“content”).innerHTML =

“This Content is showed by Android invoke Javascript function.”;

}

 

// –></script>

<body>

<p><a onClick=”window.demo.startMap()” href=””>Start GoogleMap</a></p>

<p id=”content”></p>

<p>A Demo —-Android and Javascript invoke each other.</p>

<p>Author:Frankiewei</p>

</body>

</html>

 

activity代码:

public class WebViewDemo extends Activity {

private WebView mWebView;

private Button mButton;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

setupViews();

}

//初始化

private void setupViews() {

mWebView = (WebView) findViewById(R.id.webview);

WebSettings mWebSettings = mWebView.getSettings();

//加上这句话才能使用javascript方法

mWebSettings.setJavaScriptEnabled(true);

//增加接口方法,让html页面调用

mWebView.addJavascriptInterface(new Object() {

//这里我定义了一个打开地图应用的方法

public void startMap() {

Intent mIntent = new Intent();

ComponentName component = new ComponentName(

“com.google.android.apps.maps”,

“com.google.android.maps.MapsActivity”);

mIntent.setComponent(component);

startActivity(mIntent);

}

}, “demo”);

//加载页面

mWebView.loadUrl(“file:///android_asset/demo.html”);

mButton = (Button) findViewById(R.id.button);

//给button添加事件响应,执行JavaScript的fillContent()方法

mButton.setOnClickListener(new Button.OnClickListener() {

public void onClick(View v) {

mWebView.loadUrl(“javascript:fillContent()”);

}

});

}

}

 

 

其他例子如下:(activity中获取js界面输入框的值)

Jsp中的代码:

<body>

<form action=”” method=”post”>

宝宝预产期:<br>

<select id=”shijian” name=”date”>

<option value=”2006″>2006</option>

<option value=”2007″>2007</option>

<option value=”2008″>2008</option>

<option value=”2009″>2009</option>

<option value=”2010″>2010</option>

</select><br>

常用邮箱号:

<input id=”email” type=”text” name=”emailID” />

<br>

宝宝昵称:

<input id=”name” type=”text” name=”username” />

<br>

宝宝性别:<br>

<input id=”men” type=”radio” name=”sex” value=”men”/>男

<input id=”women” type=”radio” name=”sex” value=”women”/>女

<br>

<input type=”submit” value=”注册”

οnclick=”f()”/>

<input type=”button” value=”取消” />

</form>

</body>

<script type=”text/JavaScript” language=”javascript”>

function f(){

var email = document.getElementById(’email’).value;

var name = document.getElementById(‘name’).value;

var date = document.getElementById(‘shijian’).value;

if(document.getElementById(‘men’).checked
&& !document.getElementById(‘women’).checked){

var sex = document.getElementById(‘men’).value;

}else if(!document.getElementById(‘men’).checked &&
document.getElementById(‘women’).checked){

var sex = document.getElementById(‘women’).value;

}

window.demo.clickOnAndroid(date+”|”+email+”|”+name+”|”+sex);

}

</script>

Manifest.xml中的代码:

<?xml version=”1.0″ encoding=”utf-8″?>

<manifest xmlns:android=”http://schemas.android.com/apk/res/android”

package=”com.ruixin.login” android:versionCode=”1″ android:versionName=”1.0″>

<application android:icon=”@drawable/icon” android:label=”@string/app_name”>

<activity android:name=”.TestWebviewDemo” android:label=”@string/app_name”>

<intent-filter>

<action android:name=”android.intent.action.MAIN” />

<category android:name=”android.intent.category.LAUNCHER” />

</intent-filter>

<intent-filter>

<data android:mimeType=”vnd.android.cursor.dir/vnd.ruixin.login” />

</intent-filter>

<intent-filter>

<data android:mimeType=”vnd.android.cursor.item/vnd.ruixin.login” />

</intent-filter>

 

</activity>

<provider android:name=”MyProvider” android:authorities=”com.ruixin.login” />

</application>

<uses-sdk android:minSdkVersion=”8″ />

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

<uses-permission
android:name=”android.permission.READ_CONTACTS”></uses-permission>

</manifest>

 

 

布局文件中的代码:

<?xml version=”1.0″ encoding=”utf-8″?>

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”

android:orientation=”vertical” android:layout_width=”fill_parent”

android:layout_height=”fill_parent”>

<WebView android:id=”@+id/WebView01″ android:layout_width=”fill_parent”

android:layout_height=”fill_parent”></WebView>

</LinearLayout>

 

TestWebviewDemo中的代码:

public class TestWebviewDemo extends Activity {

/** Called when the activity is first created. */

private static final String TAG = “TestWebviewDemo”;

private WebView mWebView;

private Handler mHandler = new Handler();

private int mDensity;

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

 

mWebView = (WebView) findViewById(R.id.WebView01);

mWebView.getSettings().setAllowFileAccess(true);// 设置允许访问文件数据

mWebView.getSettings().setBuiltInZoomControls(true);// 设置支持缩放

mWebView.getSettings().setSavePassword(false); // 设置是否保存密码

// 设置支持JavaScript脚本

mWebView.getSettings().setJavaScriptEnabled(true);

// 设置支持各种不同的设备

mWebView

.getSettings()

.setUserAgentString(

“Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us)
AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10”);

// 通过这个设置来执行加载webview网页时所要执行的一些方法

mWebView.setWebViewClient(new WebViewClient() {

// 新开页面时用自己定义的webview来显示,不用系统自带的浏览器来显示

public boolean shouldOverrideUrlLoading(WebView view, String url) {

// TODO Auto-generated method stub

// 当有新连接时使用当前的webview进行显示

view.loadUrl(url);

return super.shouldOverrideUrlLoading(view, url);

}

// 开始加载网页时要做的工作

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

 

super.onPageStarted(view, url, favicon);

}

//加载完成时要做的工作

public void onPageFinished(WebView view, String url) {

 

super.onPageFinished(view, url);

}

// 加载错误时要做的工作

public void onReceivedError(WebView view, int errorCode,

String description, String failingUrl) {

Log.d(TAG, “error=” + description);

Toast.makeText(TestWebviewDemo.this,

errorCode + “/” + description, Toast.LENGTH_LONG)

.show();

}

});

// 处理网页中的一些对话框信息(提示对话框,带选择的对话框,带输入的对话
框)

mWebView.setWebChromeClient(new WebChromeClient() {

// 对话框

public boolean onJsAlert(WebView view, String url, String message,

final JsResult result) {

// 构建一个Builder来显示网页中的alert对话框

Builder builder = new Builder(TestWebviewDemo.this);

builder.setTitle(“提示对话框”);

builder.setMessage(message);

builder.setPositiveButton(android.R.string.ok,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.confirm();

}

});

builder.setCancelable(false);

builder.create();

builder.show();

return true;

}

// 带按钮的对话框

public boolean onJsConfirm(WebView view, String url,

String message, final JsResult result) {

Builder builder = new Builder(TestWebviewDemo.this);

builder.setTitle(“带选择的对话框”);

builder.setMessage(message);

builder.setPositiveButton(android.R.string.ok,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.confirm();

}

 

});

builder.setNeutralButton(android.R.string.cancel,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.cancel();

}

 

});

builder.setCancelable(false);

builder.create();

builder.show();

return true;

}

// 带输入框的对话框

public boolean onJsPrompt(WebView view, String url, String message,

String defaultValue, final JsPromptResult result) {

LayoutInflater inflater = LayoutInflater

.from(TestWebviewDemo.this);

final View v = inflater.inflate(R.layout.prom_dialog, null);

// 设置 TextView对应网页中的提示信息

((TextView) v.findViewById(R.id.TextView_PROM))

.setText(message);

// 设置EditText对应网页中的输入框

((EditText) v.findViewById(R.id.EditText_PROM))

.setText(defaultValue);

Builder builder = new Builder(TestWebviewDemo.this);

builder.setTitle(“带输入的对话框”);

builder.setView(v);

builder.setPositiveButton(android.R.string.ok,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

String value = ((EditText) v

.findViewById(R.id.EditText_PROM))

.getText().toString();

result.confirm(value);

}

});

builder.setNegativeButton(android.R.string.cancel,

new AlertDialog.OnClickListener() {

 

@Override

public void onClick(DialogInterface dialog,

int which) {

// TODO Auto-generated method stub

result.cancel();

}

});

builder

.setOnCancelListener(new DialogInterface.OnCancelListener() {

 

@Override

public void onCancel(DialogInterface dialog) {

// TODO Auto-generated method stub

result.cancel();

}

 

});

builder.create();

builder.show();

return true;

 

}

 

// 设置网页加载的进度条

public void onProgressChanged(WebView view, int newProgress) {

TestWebviewDemo.this.getWindow().setFeatureInt(

Window.FEATURE_PROGRESS, newProgress * 100);

super.onProgressChanged(view, newProgress);

}

 

// 设置应用程序的标题

public void onReceivedTitle(WebView view, String title) {

TestWebviewDemo.this.setTitle(title);

super.onReceivedTitle(view, title);

}

 

});

// 与网页进行交互的addJavascriptInterface()的方法

mWebView.addJavascriptInterface(new Object() {

public void clickOnAndroid(final String str) {

mHandler.post(new Runnable() {

@Override

public void run() {

StringTokenizer stringTokenizer = new StringTokenizer(

str, “|”);

date = stringTokenizer.nextToken();

email = stringTokenizer.nextToken();

username = stringTokenizer.nextToken();

sex = stringTokenizer.nextToken();

//将数据出入数据库

dBlite1.add(email,username,date,sex);

// 用contentResolver访问存入到contentprovider中的数据

contentResolver = TestWebviewDemo.this

.getContentResolver();

Log.d(“++++”, RuiXin.CONTENT_URI.toString());

 

Cursor cursor = contentResolver.query(

RuiXin.CONTENT_URI, new String[] {

RuiXin.EMAIL, RuiXin.USERNAME,

RuiXin.DATE,RuiXin.SEX }, null, null, null);

Log.d(“@@@—-“, cursor.toString());

// startManagingCursor(cursor);

while (cursor.moveToNext()) {

Toast.makeText(

TestWebviewDemo.this,

cursor.getString(cursor.getColumnIndex(RuiXin.EMAIL))

+ ” ”

+ cursor.getString(cursor

.getColumnIndex(RuiXin.USERNAME))

+ ” ”

+ cursor.getString(cursor

.getColumnIndex(RuiXin.DATE))

+ ” ”

+ cursor.getString(cursor

.getColumnIndex(RuiXin.SEX)),

Toast.LENGTH_SHORT).show();

}

startManagingCursor(cursor); //关闭游标

}

});

}

}, “demo”);

 

if (mDensity == 240) { // 可以让不同的density的情况下,可以让页面进行适配

mWebView.getSettings().setDefaultZoom(ZoomDensity.FAR);

} else if (mDensity == 160) {

mWebView.getSettings().setDefaultZoom(ZoomDensity.MEDIUM);

} else {

mWebView.getSettings().setDefaultZoom(ZoomDensity.CLOSE);

}

String strUrl = “http://10.0.2.2:8080/WebTest3”;

mWebView.loadUrl(strUrl);

}

//处理返回的事件,(后退进入前一个界面而不是全部退出)

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {

mWebView.goBack();// 返回前一个页面

return true;

}

return super.onKeyDown(keyCode, event);

}

 

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速