Android中处理Touch Icon的方案

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

Touch Icon

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

<span style="font-family:Arial;font-size:14px;"><link rel="apple-touch-icon" href="/custom_icon.png"></span>

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

<span style="font-family:Arial;font-size:14px;"><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"></span>

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

<span style="font-family:Arial;font-size:14px;"><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"></span>

加载网页,onReceivedTouchIconUrl输出的日志

<span style="font-family:Arial;font-size:14px;"><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"></span>

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

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代码中对应的回调。

<span style="font-family:Arial;font-size:14px;">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();</span>

Java代码

这里为了便于理解还是全部贴出了demo的源码,demo中当网页加载完成之后注入上面的js代码获取touch icon信息,然后返回给java的回调方法中。如果不清楚Java代码如何实现改进方案的,可以点击Java代码编写的Android应用如何实现安全

<span style="font-family:Arial;font-size:14px;">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();
  }
}</span>

返回的JSON数据

<span style="font-family:Arial;font-size:14px;">[
  {
      "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"
  }
]</span>

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

Google会改进么

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

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

<span style="font-family:Arial;font-size:14px;"><link rel="manifest" href="manifest.json"></span>

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

<span style="font-family:Arial;font-size:14px;">{
  "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"
}</span>

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

源码下载:http://pan.baidu.com/s/1dDD3gZZ

时间: 2024-10-06 19:31:48

Android中处理Touch Icon的方案的相关文章

android中根据touch事件判断单击及双击

private static final int MAX_INTERVAL_FOR_CLICK = 250;     private static final int MAX_DISTANCE_FOR_CLICK = 100;     private static final int MAX_DOUBLE_CLICK_INTERVAL = 500;     int mDownX = 0;     int mDownY = 0;     int mTempX = 0;     int mTempY

Android中Touch手势分发

在android中的Touch分发中,经常可以看到从ACTION_DOWN->ACTION_MOVE->ACTION_UP,当我们不了解它是如何分发的话总感觉一头雾水,所以有必要了解它的整体分发过程,所以很有必要好好的记录下. 事件分发函数 public void dispatchTouchEvent(MotionEvent ev). public void onInterceptTouchEvent(MotionEvent ev). public void onTouchEvent(Moti

Android中线程间通信原理分析:Looper,MessageQueue,Handler

自问自答的两个问题 在我们去讨论Handler,Looper,MessageQueue的关系之前,我们需要先问两个问题: 1.这一套东西搞出来是为了解决什么问题呢? 2.如果让我们来解决这个问题该怎么做? 以上者两个问题,是我最近总结出来的,在我们学习了解一个新的技术之前,最好是先能回答这两个问题,这样你才能对你正在学习的东西有更深刻的认识. 第一个问题:google的程序员们搞出这一套东西是为了解决什么问题的?这个问题很显而易见,为了解决线程间通信的问题.我们都知道,Android的UI/Vi

Android中dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent的理解

[转]http://blog.csdn.net/guitk/article/details/7057155 onInterceptTouchEvent用于改变事件的传递方向.决定传递方向的是返回值,返回为false时事件会传递给子控件,返回值为true时事件会传递给当前控件的onTouchEvent(),这就是所谓的Intercept(拦截). [tisa ps:正确的使用方法是,在此方法内仅判断事件是否需要拦截,然后返回.即便需要拦截也应该直接返回true,然后由onTouchEvent方法进

Android中常见IPC方法总结

欢迎转载,转载请注明出处http://blog.csdn.net/l664675249/article/details/50654926 IPC (Interprocess communication)跨进程通信,是指在两个进程之间交换数据的过程.多进程通信一般分为两种情况.第一种,一个应用因为自身的需要采用多进程实现,比如某些模块由于特殊原因需要运行在单独的进程中.第二种情况,当前应用需要获得其它应用的数据,由于是两个应用,所以必须采用跨进程的方式.下面就对常用的IPC方法做一个总结. 使用B

Android 编程下 Touch 事件的分发和消费机制

Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev).onTouchEvent(MotionEvent ev):能够响应这些方法的控件包括:ViewGroup 及其子类.Activity.方法与控件的对应关系如下表所示: Touch 事件相关方法   方法功能     ViewGroup         Activity        public b

Android 根据规划 Touch 分配和消费机制的事件

Android 中与 Touch 事件相关的方法包含:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev).onTouchEvent(MotionEvent ev):可以响应这些方法的控件包含:ViewGroup.View.Activity.方法与控件的相应关系例如以下表所看到的: Touch 事件相关方法   方法功能     ViewGroup          View             Ac

android中的事件分发和消费机制

一.思维导图 查看大图:http://img.blog.csdn.net/20150524191211931 二.更多参考 Android中的Touch事件处理:http://www.cnblogs.com/mengdd/p/3394345.html Android 编程下 Touch 事件的分发和消费机制 :http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html Android事件分发完全解析之为什么是她:http://blog

Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()

Android中触摸事件传递过程中最重要的是dispatchTouchEvent().onInterceptTouchEvent()和onTouchEvent()方法.这个是困扰初学者的问题之一,我开始也是.这里记录一下dispatchTouchEvent().onInterceptTouchEvent()和onTouchEvent()的处理过程,以供记忆. dispatchTouchEvent是处理触摸事件分发,事件(多数情况)是从Activity的dispatchTouchEvent开始的.