欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中处理apple-touch-icon详解

程序员文章站 2022-04-12 12:25:28
苹果的touch icon相对我们都比较熟悉,是苹果为了支持网络应用(或者说网页)添加到桌面需要的图标,有了这些touch icon的网页链接更加和native应用更相像了...

苹果的touch icon相对我们都比较熟悉,是苹果为了支持网络应用(或者说网页)添加到桌面需要的图标,有了这些touch icon的网页链接更加和native应用更相像了。由于苹果设备ipod,iphone,ipad等设备广泛,很多网页都提供了touch icon这种图标资源。由于android中并没有及早的有一份这样的标准,当我们想把网页添加到桌面时,仍然需要使用苹果的touch icon。

touch icon

当我们想让一个网页比较完美地添加到桌面,通常情况下我们需要设置一个png图片文件作为apple-touch-icon。比如:

复制代码 代码如下:

<link rel="apple-touch-icon" href="/custom_icon.png">

如果想支持iphone和ipad,我们需要使用sizes属性来制定多个图片,默认sizes的值为60 x 60。

复制代码 代码如下:

<link rel="apple-touch-icon" href="touch-icon-iphone.png">
<link rel="apple-touch-icon" sizes="76x76" href="touch-icon-ipad.png">
<link rel="apple-touch-icon" sizes="120x120" href="touch-icon-iphone-retina.png">
<link rel="apple-touch-icon" sizes="152x152" href="touch-icon-ipad-retina.png">

在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的顺序不规律

复制代码 代码如下:

<link rel="apple-touch-icon-precomposed" sizes="72x72" href="http://www.qiyipic.com/20130423143600/fix/h5-72x72.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="http://www.qiyipic.com/20130423143600/fix/h5-114x114.png">
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="http://www.qiyipic.com/20130423143600/fix/h5-57x57.png">
<link rel="apple-touch-icon-precomposed"  href="http://www.qiyipic.com/20130423143600/fix/h5-0x0.png">

加载网页,onreceivedtouchiconurl输出的日志

复制代码 代码如下:

i/mainactivity( 6995): onreceivedtouchiconurl url=http://www.qiyipic.com/20130423143600/fix/h5-0x0.png;precomposed=true
i/mainactivity( 6995): onreceivedtouchiconurl url=http://www.qiyipic.com/20130423143600/fix/h5-57x57.png;precomposed=true
i/mainactivity( 6995): onreceivedtouchiconurl url=http://www.qiyipic.com/20130423143600/fix/h5-114x114.png;precomposed=true
i/mainactivity( 6995): onreceivedtouchiconurl url=http://www.qiyipic.com/20130423143600/fix/h5-72x72.png;precomposed=true

从上面的输出来看,基本上是后面(书写)的元素先打印出来,所以这个回调的缺陷如下

1.由于touch icon url地址没有硬性规定,不能根据url包含某些尺寸来判断使用哪个icon
2.由于网页编写touch icon元素相对随意,不能根据onreceivedtouchiconurl调用先后来决定使用哪个icon
3.回调中没有sizes属性值,不好确定使用哪个icon
4.如果我们选取质量最高的图片,然后进行适当压缩处理或许可以解决问题,但是将全部icon下载下来或者根据head头信息总感觉不怎么好。

改进方法

既然webview没有现成的方法满足我们的需求,只好自己来实现。其实实现方法还是比较简单地就是js脚本注入检测网页元素中得touch icon,返回json数据。

javascript方法

下面的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和javascript交互,可以访问android中java和javascript交互了解更多。

复制代码 代码如下:

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.javascriptinterface;
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().setjavascriptenabled(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("javascript:" + touchiconjscode);
          }
      });
      webview.addjavascriptinterface(new jsobject(), "app_native");
      webview.loadurl("http://192.168.1.5:8000/html/touchicon.html");
  }

 
  private class jsobject {
     
      @javascriptinterface
      public void onreceivedtouchicons(string url, string json) {
          log.i(logtag, "onreceivedtouchicons url=" + url + ";json=" + json);
      }
  }
 
  private string gettouchiconjscode() {
      stringbuilder total = new stringbuilder();
      inputstream inputstream = null;
      bufferedreader bufferreader = null;
      try {
          inputstream = getassets().open("touchicon.js");
          bufferreader = new bufferedreader(new inputstreamreader(inputstream));
          string line;
          while ((line = bufferreader.readline()) != null) {
              total.append(line);
          }
      } catch (filenotfoundexception e) {
          e.printstacktrace();
      } catch (ioexception e) {
          e.printstacktrace();
      } finally {
          if (null != inputstream) {
              try {
                  inputstream.close();
              } catch (ioexception e) {
                  e.printstacktrace();
              }
          }
      }
      return total.tostring();
  }
}

返回的json数据

复制代码 代码如下:

[
  {
      "sizes":"72x72",
      "rel":"apple-touch-icon-precomposed",
      "href":"http://www.qiyipic.com/20130423143600/fix/h5-72x72.png"
  },
  {
      "sizes":"114x114",
      "rel":"apple-touch-icon-precomposed",
      "href":"http://www.qiyipic.com/20130423143600/fix/h5-114x114.png"
  },
  {
      "sizes":"57x57",
      "rel":"apple-touch-icon-precomposed",
      "href":"http://www.qiyipic.com/20130423143600/fix/h5-57x57.png"
  },
  {
      "sizes":"",
      "rel":"apple-touch-icon-precomposed",
      "href":"http://www.qiyipic.com/20130423143600/fix/h5-0x0.png"
  }
]

我们可以对得到的json数据按照需要处理。

google会改进么

答案是会,而且已经改进,但google修改的不是onreceivedtouchiconurl这个方法,而是google正在推行自己的一套规则。

在chrome上,google增加了这样一个元素,这是google提供的为网页程序定义元数据的方法。

复制代码 代码如下:

<link rel="manifest" href="manifest.json">

在元数据json中,你可以自定义title,起始页,程序是横屏还是竖屏展示。一个简单地json实例如下,这里我们可以看到其中icons中存在多个类似touch icon的图标,src代表图标路径,sizes代表大小,type就是mimetype,density指的是android中的屏幕密度(这样更加android化了)。

复制代码 代码如下:

{
  "name": "web application manifest sample",
  "icons": [
    {
      "src": "launcher-icon-0-75x.png",
      "sizes": "36x36",
      "type": "image/png",
      "density": "0.75"
    },
    {
      "src": "launcher-icon-1x.png",
      "sizes": "48x48",
      "type": "image/png",
      "density": "1.0"
    },
    {
      "src": "launcher-icon-1-5x.png",
      "sizes": "72x72",
      "type": "image/png",
      "density": "1.5"
    },
    {
      "src": "launcher-icon-2x.png",
      "sizes": "96x96",
      "type": "image/png",
      "density": "2.0"
    },
    {
      "src": "launcher-icon-3x.png",
      "sizes": "144x144",
      "type": "image/png",
      "density": "3.0"
    },
    {
      "src": "launcher-icon-4x.png",
      "sizes": "192x192",
      "type": "image/png",
      "density": "4.0"
    }
  ],
  "start_url": "index.html",
  "display": "standalone",
  "orientation": "landscape"
}

关于google这套新的标准,可以参考add to homescreen 

但是由于目前,这种标准实施率相对比较低,所以我们还是需要使用苹果的touch icon。