Touch Icon
当我们想让一个网页比较完美地添加到桌面,通常情况下我们需要设置一个png图片文件作为apple-touch-icon。比如
如果想支持IPhone和IPad,我们需要使用sizes属性来制定多个图片,默认sizes的值为60 x 60。
在IOS7之前,苹果系统会对添加到桌面的图标进行圆角化等视觉上的处理,为了不让其处理,我们可以使用apple-touch-icon-precomposed来作为rel的值实现。
更多关于Touch Icon的信息,可以访问水果开发者网站了解更多。
Android中有缺陷的实现
在Android WebView提供了处理Touch Icon的回调,onReceivedTouchIconUrl(WebView view, String url,boolean precomposed)该方法返回了对我们有用的touch icon的url,和是否为预组合(在IOS中不需要进行视觉处理)。虽然有这些数据,我们可以进行处理,但是这其中是有问题的,就是我们不好确定文件的大小,来选择适合的图片。
举个例子,如下一个网页的源码,其中sizes的顺序不规律
加载网页,onReceivedTouchIconUrl输出的日志
从上面的输出来看,基本上是后面(书写)的元素先打印出来,所以这个回调的缺陷如下
1.由于Touch Icon url地址没有硬性规定,不能根据url包含某些尺寸来判断使用哪个icon
2.由于网页编写touch icon元素相对随意,不能根据onReceivedTouchIconUrl调用先后来决定使用哪个icon
3.回调中没有sizes属性值,不好确定使用哪个icon
4.如果我们选取质量最高的图片,然后进行适当压缩处理或许可以解决问题,但是将全部icon下载下来或者根据Head头信息总感觉不怎么好。
改进方法
既然WebView没有现成的方法满足我们的需求,只好自己来实现。其实实现方法还是比较简单地就是js脚本注入检测网页元素中得touch icon,返回json数据。
java script方法
下面的JS代码所做的功能为查找所有为touch icon的link元素,包含正常的还标记为precomposed。然后将这些link元素的属性存入json数据,最后返回给Java代码中对应的回调。
var touchIcons = [];
function gatherTouchIcons(elements) {
? var normalTouchIconLength = elements.length;
? var currentElement;
? for (var i =0; i < normalTouchIconLength;i++) {
? ? ? currentElement = elements[i];
? ? ? var size;
? ? ? if (currentElement.hasAttribute('sizes')) {
? ? ? ? ? size = currentElement.sizes[0];
? ? ? } else {
? ? ? ? ? size = '';
? ? ? }
? ? ? var info = {'sizes':size, 'rel': currentElement.rel, 'href': currentElement.href};
? ? ? touchIcons.push(info);
? }
}
?
function obtainTouchIcons() {
? normalElements = document.querySelectorAll("link[rel='apple-touch-icon']");
? precomposedElements = document.querySelectorAll("link[rel='apple-touch-icon-precomposed']");
? gatherTouchIcons(normalElements);
? gatherTouchIcons(precomposedElements);
? var info = JSON.stringify(touchIcons);
? window.app_native.onReceivedTouchIcons(document.URL, info);
}
obtainTouchIcons();
Java代码
这里为了便于理解还是全部贴出了demo的源码,demo中当网页加载完成之后注入上面的js代码获取touch icon信息,然后返回给java的回调方法中。如果不清楚Java代码如何实现改进方案的,可以点击Java代码编写的Android应用如何实现安全
package com.example.obtaintouchicon;
?
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
?
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.java scriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
?
public class MainActivity extends Activity {
?
? protected String LOGTAG = "MainActivity";
?
? @Override
? protected void onCreate(Bundle savedInstanceState) {
? ? ? super.onCreate(savedInstanceState);
? ? ? WebView webView = new WebView(this);
? ? ? webView.getSettings().setjava scriptEnabled(true);
? ? ? webView.setWebViewClient(new WebViewClient() {
? ? ? ? ? @Override
? ? ? ? ? public void onPageFinished(WebView view, String url) {
? ? ? ? ? ? ? super.onPageFinished(view, url);
? ? ? ? ? ? ? final String touchIconJsCode = getTouchIconJsCode();
? ? ? ? ? ? ? Log.i(LOGTAG , "onPageFinished url = " + url + ";touchIconJsCode=" + touchIconJsCode);
? ? ? ? ? ? ? view.loadUrl("java script:" + touchIconJsCode);
? ? ? ? ? }
? ? ? });
? ? ? webView.addjava scriptInterface(new JsObject(), "app_native");
? ? ? webView.loadUrl("http://192.168.1.5:8000/html/touchicon.html");
? }
?
? ?
? p