Details of ES1en ES2en ES3en in Android

  • 2020-06-12 10:34:56
  • OfStack

Apple's Touch Icon is a familiar icon that Apple needs to add to the desktop in order to support web apps (or web pages). With these links, Touch Icon's web links are more like Native's apps. Due to the wide range of Apple devices like IPod, IPhone and IPad, many web pages offer touch icon as icon resources. Since there wasn't an earlier version of this standard in Android, we still needed to use Apple's Touch Icon when we wanted to add web pages to the desktop.

Touch Icon

When we want a page to be added perfectly to the desktop, we usually need to set up an png image file as ES20en-ES21en-ES22en. Such as:


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

If we want to support IPhone and IPad, we need to use the sizes attribute to make multiple images. The default value of sizes is 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">

Before IOS7, The Apple system did visual manipulation such as rounding ICONS added to the desktop. To prevent it, we can use ES39en-ES40en-ES41en-ES42en as the value of rel.

For more information on Touch Icon, visit the fruit Developer website for more information.

Defective implementation in Android

In Android WebView the callback is provided for processing Touch Icon, onReceivedTouchIconUrl(WebView view, String url,boolean precomposed) this method returns url of touch icon which is useful to us, and whether it is pre-combined (no visual processing is required in IOS). Although there is such data, we can handle it, but there is a problem, is that we can not determine the size of the file, to choose the right picture.

For example, the following page source code, sizes order is irregular


<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">

Load the page, onReceivedTouchIconUrl output log


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

Based on the output above, basically the elements that follow (write) are printed first, so the drawback of this callback is as follows

1. Since there is no hard and fast rule on the address of Touch Icon url, it is not possible to judge which icon to use based on the size of url
2. Since touch icon elements are written relatively casually, it is not possible to decide which icon to use based on the sequence of onReceivedTouchIconUrl calls
3. There is no sizes attribute value in the callback, so it is difficult to determine which icon to use
4. If we had taken the highest quality image and compressed it appropriately, we might have solved the problem, but downloading the entire icon or based on the Head headers doesn't always feel good.

Improved method

Since WebView had no ready-made way to meet our needs, we had to implement it ourselves. In fact, the implementation method is still relatively simple is js script injection detection page elements touch icon, return json data.

JavaScript method

All the JS code below does is find all link elements that are touch icon, including the normal ones that are also marked precomposed. The attributes of these link elements are then stored in the json data and returned to the corresponding callback in the Java code.


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 code

The source code of demo is posted here for easy understanding. demo infuses the above js code to obtain touch icon information after the web page is loaded, and then returns to the callback method of java. If you are not aware of the Java and JavaScript interactions, you can visit the Java and JavaScript interactions in Android for more information.


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 data returned


[
  {
      "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"
  }
]

We can process the obtained JSON data as required.

Will Google improve

The answer is yes, and it has improved, but Google is not modifying the onReceivedTouchIconUrl method, but Google is implementing its own set of rules.

On Chrome, Google added this element, which is the way Google defines metadata for web applications.


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

In json metadata, you can customize title, the start page, and whether the application is displayed in landscape or portrait. A simple example of json is shown below, where we can see that there are several ICONS similar to touch icon in icons, src for icon path, sizes for size, type for screen density in Android (which is more 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"
}

For the new Google standard, please refer to Add to Homescreen

However, since the implementation rate of this standard is relatively low at present, we still need to use Apple's touch icon.


Related articles: