官网简单翻译。。
Web Apps
在安卓平台上, 你可以使用apk安装一个应用或者通过浏览器打开一个web应用。如果选择了后者,你可以通过浏览器或者apk应用内嵌的webView框架为web页面定制viewport和风格属性。
web和android之间可以通过JavaScript进行交互。
相关链接
这里是为设计web页面的同学提供的。。
Pixel-Perfect UI in the WebView
Creating a Mobile-First Responsive Web Design
为不同的像素密度设置HDPI图片
制作支持不同的屏幕web页面
viewport
viewport是一个显示web页面、可拖拽的矩形区域。你可以设置他的一些属性,比如尺寸和比例。最主要的还是width
viewport的长宽和屏幕的长宽是各自独立的。比如设备宽如果为480像素,viewport可以是480,也可以是800(800时会有横条)。
WebView默认是将页面 适应屏幕缩放的。
对page的viewport设置(所有属性请看原文):
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
</head>
屏幕密度
CSS的像素值会在安卓上自动转换成DP单位。要注意
WebView内置了CSS媒体元素来支持DP,如下:
<link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.5)" href="hdpi.css" />
其中1.5可以为0.75,1.0,1.5。或者可以在样式表中定义。。。
在JS中获取DP值
if (window.devicePixelRatio == 1.5) {
alert("This is a high-density screen");
} else if (window.devicePixelRatio == 0.75) {
alert("This is a low-density screen");
}
使用WebView
webView继承自view,没什么多余功能,默认情况下就是单纯显示页面。
常见的使用场景是 用户协议、用户指导等可能经常更新布局(如果布局不变,也可以用activity,个人认为)的页面。
另一个场景是经常要联网检索数据的时候,比如email。
直接使用WebView
布局中添加,代码中find后,直接加载页面:
myWebView.loadUrl("http://www.example.com");
使用JS
启用JS
通过WebSettings
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
绑定JS和Android代码
//android端WebView,创建名为Android的接口
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
//调用的WebAppInterface
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
//如果Android4.2及以上,需要加标注
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
//JS端
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
- WebView自动初始化Android接口
- JS调用的对象运行在另一个线程,而不是在创建的线程。
- addJavascriptInterface()会使JS可以控制android应用。所以要注意页面来源和相关防范
处理导航
当点击WebView里的链接的时候,默认的方式是打开默认浏览器加载链接。你可以重写该操作,来让你的WebView自身加载链接,并且处理相关的前进和后退操作。
通过WebViewClient
//此时就可以用webView自己处理链接加载了
myWebView.setWebViewClient(new WebViewClient());
//通过重写获取更多控制
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals("www.example.com")) {
// This is my web site, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
历史导航
如果你已经重写了shouldOverrideUrlLoading,可以如下控制前进和后退(注意这只是根据浏览记录的前进和后退,不会按层级识别。比如你从1页面进入2页面,再通过按钮“返回”1页面,再进入2页面,则会依次返回,而不是直接返回1后退出。)
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
在Android4.4集成WebView
4.4的WebView基于Chromium。提升了性能,并且更新HTML5,CSS3和JS标准以匹配最新的浏览器。
如果targetSdkVersion在18及以下,WebView会以quirks mode来禁止一些行为变化,当然它会尽可能的保证性能和web的一些标准。比如在4.4以上的机子运行这个app时,不能完全支持单一狭窄的列布局和默认的缩放等级。所以,尽管targetSdkVersion表示不考虑更新的平台,但是还是需要测试一下。
可以通过setWebContentsDebuggingEnabled()来使用桌面版Chrome调试。更多查看用chrome远程调试android
用户代理改变
//现在多了个chrome版本
Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16H) AppleWebKit/537.36
(KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
获取代理:
- getDefaultUserAgent(),检索代理并且可以不保存、不实例化WebView
- getUserAgentString(),重写代理字符串
多线程和锁死线程
- 请确保在主线程调用WebView的方法,否则会有预期之外的结果。
- 确保不要锁死UI线程。比如等待JS回调时,可以用evaluateJavascript()异步运行JS
自定义URL处理
新的WebView在用自定义URL主题,进行资源请求和链接处理的时候添加了很多限制,比如只在url合法的时候调用shouldOverrideUrlLoading() or shouldInterceptRequest(),
如果在4.4上回调的数量很少或者加载资源失败,请确认下url是否符合RFC3986。
比如:
//WebView不会在点击这个链接时调用shouldOverrideUrlLoading(),
<a href="showProfile">Show Profile</a>
用户点击的时候会有不同的结果:
如果你使用非合法或者空的base Url来loadData()或loadDataWithBaseURL(),以加载页面。那么你在这个页面的这一类链接都不会回调shouldOverrideUrlLoading()
注意如果loadDataWithBaseURL()时,baseUrl是非合法的或者空的,那么内容里的链接必须是绝对路径。
如果加载页面通过loadUrl,或者使用合法的baseUrl来loadDataWithBaseURL(),那么你就会收到回调。但是你获取的url是 “http://www.example.com/showProfile“(相对于你baseUrl的绝对路径),而不只是showProfile
你可以在页面这么自定义主题:
<a href="example-app:showProfile">Show Profile</a>
然后处理:
// The URL scheme should be non-hierarchical (no trailing slashes)
private static final String APP_SCHEME = "example-app:";
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(APP_SCHEME)) {
urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
respondToData(urlData);
return true;
}
return false;
}
如果没法改变HTML,可以自己加一个baseUrl以组成合法的地址
webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA,
null, "UTF-8", null);
Viewport改变
- target-densitydpi属性不再支持,请参照相关链接里的 Pixel-Perfect UI in the WebView 文章。
- 之前的viewport宽如果小于320,高如果小于WebView的高,会默认改成设备的宽高。现在viewport不变,WebView会放大它到适应屏幕宽度。
- 不再支持多个tags。现在只承认最后定义的tag
- 默认缩放已经过时。不再支持 getDefaultZoom() and setDefaultZoom() 。
4.4及以上的API已不支持,所以。。。
如果你不能在html设置viewport的宽度,那么调用setUseWideViewPort()来保证为page配置了个更大的viewport
WebSettings settings = webView.getSettings();
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
风格改变
background CSS shorthand 覆盖 background-size
如果你设置了background style,那么这样写的话,background-size会被重置成默认值。
.some-class {
background-size: contain;
background: url('images/image.png') no-repeat;
}
修正方法是将background-size写在下面。
大小使用CSS像素,而不是屏幕像素
如果你设置缩放不可用并且初始化比例为1.0,那么可以使用window.devicePixelRatio获取缩放比例,然后乘以CSS像素值。否则就使用和JS交互的方式获取像素大小。更多查看quirksmode.org
单一或狭窄的列不再支持
不再支持NARROW_COLUMNS value for WebSettings.LayoutAlgorithm
你可以做如下处理:
- 最好是修改HTML或者CSS,…
- …
注:…处都是页面修改什么的,不懂,忽略了。下同。如有需要,可查看原文
用JS处理触摸事件
…
调试WebApps
在Android浏览器中使用Console APIs
…
在WebView中使用Console APIs
android2.1以上,你必须提供实现 onConsoleMessage() 的 WebChromeClient,这样才可以获取logcat。
支持API 7,则使用 onConsoleMessage(String, int, String) ,8及以上使用:
myWebView.setWebChromeClient(new WebChromeClient() {
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d("MyApplication", cm.message() + " -- From line "
+ cm.lineNumber() + " of "
+ cm.sourceId() );
return true;
}
});
ConsoleMessage包含了一个MessageLevel对象,可以通过messageLevel()方法获取消息等级以做出相应的处理。
消息示例:
Hello World -- From line 82 of http://www.example.com/hello.html
WebApps最佳实践
…
WebView
api文档中,上面没提到的代码部分
//= = 一般性起码加个ProgressBar吧。。
WebView webview = new WebView(this);
setContentView(webview);
// 加载HTML字符串,
String summary = "<html><body>You scored <b>192</b> points.</body></html>";
webview.loadData(summary, "text/html", null);
//配合title bar设置进度
getWindow().requestFeature(Window.FEATURE_PROGRESS);
webview.getSettings().setJavaScriptEnabled(true);
final Activity activity = this;
webview.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
// Activities and WebViews measure progress with different scales.
// The progress meter will automatically disappear when we reach 100%
activity.setProgress(progress * 1000);
}
});
webview.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();
}
});
webview.loadUrl("http://developer.android.com/");