跨端小程序如何识别当前的容器(APP)

321 阅读2分钟

1.index.js

import detect from './detect';
console.log(detect.app.name);

2.detect.js

import CheckApp from "./checkApp";
var detect = {},
    NA_VERSION = "-1",
    userAgent = navigator.userAgent || "",
    appVersion = navigator.appVersion || "",
    vendor = navigator.vendor || "",
    external = window.external,
    re_msie = /\b(?:msie |ie |trident\/[0-9].*rv[ :])([0-9.]+)/;

// var CheckApp = require('./checkApp');

function toString(object) {
    return Object.prototype.toString.call(object);
}

function isObject(object) {
    return toString(object) === "[object Object]";
}

function isFunction(object) {
    return toString(object) === "[object Function]";
}

function each(object, factory, argument) {
    for (var i = 0, b, l = object.length; i < l; i++) {
        if (factory.call(object, object[i], i) === false) {
            break;
        }
    }
}

// 操作系统信息识别表达式
var OS = [
    ["wp",
        function(ua) {
            if (ua.indexOf("windows phone ") !== -1) {
                return /\bwindows phone (?:os )?([0-9.]+)/;
            } else if (ua.indexOf("xblwp") !== -1) {
                return /\bxblwp([0-9.]+)/;
            } else if (ua.indexOf("zunewp") !== -1) {
                return /\bzunewp([0-9.]+)/;
            }
            return "windows phone";
        }
    ],
    ["ios",
        function(ua) {
            if (/\bcpu(?: iphone)? os /.test(ua)) {
                return /\bcpu(?: iphone)? os ([0-9._]+)/;
            } else if (ua.indexOf("iph os ") !== -1) {
                return /\biph os ([0-9_]+)/;
            } else {
                return /\bios\b/;
            }
        }
    ],
    ["yunos", /\baliyunos ([0-9.]+)/],
    ["android", /\bandroid[\/\- ]?([0-9.x]+)?/],
    ["linux", "linux"]
];

var BROWSER = [
    ["qq", /\bm?qqbrowser\/([0-9.]+)/],
    // 后面会做修复版本号,这里只要能识别是 IE 即可。
    ["ie", re_msie],
    ["chrome", / (?:chrome|crios|crmo)\/([0-9.]+)/],
    // UC 浏览器,可能会被识别为 Android 浏览器,规则需要前置。
    ["uc",
        function(ua) {
            if (ua.indexOf("ucbrowser/") >= 0) {
                return /\bucbrowser\/([0-9.]+)/;
            } else if (/\buc\/[0-9]/.test(ua)) {
                return /\buc\/([0-9.]+)/;
            } else if (ua.indexOf("ucweb") >= 0) {
                return /\bucweb[\/]?([0-9.]+)?/;
            } else {
                return /\b(?:ucbrowser|uc)\b/;
            }
        }
    ],
    // Android 默认浏览器。该规则需要在 safari 之前。
    ["android",
        function(ua) {
            if (ua.indexOf("android") === -1) {
                return;
            }
            return /\bversion\/([0-9.]+(?: beta)?)/;
        }
    ],
    ["safari", /\bversion\/([0-9.]+(?: beta)?)(?: mobile(?:\/[a-z0-9]+)?)? safari\//],
    // 如果不能被识别为 Safari,则猜测是 WebView。
    ["webview", /\bcpu(?: iphone)? os (?:[0-9._]+).+\bapplewebkit\b/]
];

/**
 * UserAgent Detector.
 * @param {String} ua, userAgent.
 * @param {Object} expression
 * @return {Object}
 *    返回 null 表示当前表达式未匹配成功。
 */
function detector(name, expression, ua) {
    var expr = isFunction(expression) ? expression.call(null, ua) : expression;
    if (!expr) {
        return null;
    }
    var info = {
        name: name,
        version: NA_VERSION,
        codename: ""
    };

    // 增减判断设备是phone还是pad的逻辑(android 和 ios)
    if (name === 'android') {
        //https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent
        info.type = (ua.indexOf('Mobi') > -1 ? 'phone' : 'pad');
    }

    if (name === 'ios') {
        info.type = (ua.indexOf('iPhone') > -1 ? 'phone' : 'pad');
    }

    var t = toString(expr);
    if (expr === true) {
        return info;
    } else if (t === "[object String]") {
        if (ua.indexOf(expr) !== -1) {
            return info;
        }
    } else if (isObject(expr)) { // Object
        if (expr.hasOwnProperty("version")) {
            info.version = expr.version;
        }
        return info;
    } else if (expr.exec) { // RegExp
        var m = expr.exec(ua);
        if (m) {
            if (m.length >= 2 && m[1]) {
                info.version = m[1].replace(/_/g, ".");
            } else {
                info.version = NA_VERSION;
            }
            return info;
        }
    }
}

var na = {
    name: "na",
    version: NA_VERSION
};
// 初始化识别。
function init(ua, patterns, factory, detect) {
    var detected = na;
    each(patterns, function(pattern) {
        var d = detector(pattern[0], pattern[1], ua);
        if (d) {
            detected = d;
            return false;
        }
    });
    factory.call(detect, detected.name, detected.version);
}

/**
 * 解析 UserAgent 字符串
 * @param {String} ua, userAgent string.
 * @return {Object}
 */
var parse = function(ua) {
    ua = (ua || "").toLowerCase();
    var d = {};

    init(ua, OS, function(name, version) {
        var v = parseFloat(version);
        d.os = {
            name: name,
            version: v,
            fullVersion: version
        };
        d.os[name] = v;
    }, d);

    init(ua, BROWSER, function(name, version) {
        var v = parseFloat(version);
        d.browser = {
            name: name,
            version: v,
            fullVersion: version,
        };
        d.browser[name] = v;
    }, d);
    return d;
};

detect = parse(userAgent + " " + appVersion + " " + vendor);
detect.parse = parse;

detect._checkApp = CheckApp;
detect.app = detect._checkApp(userAgent);

module.exports = detect;

3.checkApp.js

/**
 * 解析 UserAgent 字符串
 * @param {String} ua, userAgent string.
 * @return {Object}
 *
 * "app": {
 *      "is": true,
 *      "name": "TB|TM|JU|LW|DD|ET|XM|...",  // 详见 http://velocity.alibaba-inc.com/projects/cross-end-web/wiki/App-ua
 *      "version": "9.0"
 *  }
 */
var checkApp = function(ua) {
  var app = {
    is: false,
    name: "",
    version: ""
  };
  var aliApp = ua.match(/AliApp\S+\b\)/ig);
  app.is = /(T-UA)|(TBIOS)|(WindVane)|(AliApp)/i.test(ua) ? true : false;

  try {
    app.name = aliApp ? aliApp[0].match(/\(\w+\-*\w*/)[0].split("(")[1] : "";
    app.version = aliApp ? aliApp[0].match(/(\d+\.*)+/ig)[0] : "";
  } catch (_) {}
  return app;
};

module.exports = checkApp;