从html5打开本地的app–如果本地没有app就跳转到下载页面,大家都会认为这是一项很简单的操作。网上的教程也很多,但是可行性都不高。因为手机系统和浏览器型号各不相同,所以兼容性会是让各个前端工程师头疼的问题。我们不妨看一下京东是如何解决的。京东的原代码已经混淆过了,我只能一点点反混淆并注释。
1 (function(){
2 // 判断浏览器
3 var Navigator = navigator.userAgent;
4 var ifChrome = Navigator.match(/Chrome/i) != null && Navigator.match(/Version\/\d+\.\d+(\.\d+)?\sChrome\//i) == null ? true : false;
5 var ifAndroid = (Navigator.match(/(Android);?[\s\/]+([\d.]+)?/)) ? true : false;
6 var ifiPad = (Navigator.match(/(iPad).*OS\s([\d_]+)/)) ? true : false;
7 var ifiPhone = (!ifiPad && Navigator.match(/(iPhone\sOS)\s([\d_]+)/)) ? true : false;
8 var ifSafari = (ifiPhone || ifiPad) && Navigator.match(/Safari/);
9 var version = 0;
10 ifSafari && (version = Navigator.match(/Version\/([\d\.]+)/));
11
12 version = parseFloat(version[1], 10);
13 // 是否从微信打开
14 var ifWeixin = navigator.userAgent.indexOf("MicroMessenger") >= 0; // weixin
15 var j = false;
16 var iframe = "plugIn_downloadAppPlugIn_loadIframe";
17 var t = false;
18 var i = 0;
19 var B = {};
20 var b = {};
21 var selector = null;
22 var Hquery = {};
23 // 判断当前使用的js框架是zepto还是jquery
24 var Query = window.Zepto || window.jQuery ? true : false;
25 var g = [];
26 // 是否存在html5的localStorage 存储
27 var v = window.localStorage ? true : false;
28 var o = "mdownloadAppPlugInskip";
29 var p = null;
30
31 function m() { // 打印时间 例如:2016-5-18
32 var M = new Date();
33 var N = M.getFullYear();
34 var O = M.getMonth() + 1;
35 var L = M.getDate();
36 strDate = N + "-" + O + "-" + L;
37 return strDate
38 }
39 // 微信相关操作
40 function r() { // weixin api
41 WeixinJSBridge.invoke("getInstallState", {
42 packageName: "com.jingdong.app.mall",
43 packageUrl: "openApp.jdMobile://"
44 }, function(M) {
45 var N = M.err_msg,
46 L = 0;
47 if (N.indexOf("get_install_state:yes") > -1) {
48 j = true
49 }
50 })
51 }
52 // 根据是否存在js框架进行dom和时间的绑定
53 function bind(dom, event, fun) { // bind event
54 if (Query) {
55 selector("#" + dom).bind(event, fun)
56 } else {
57 selector("#" + dom).addEventListener(event, fun, !1)
58 }
59 }
60
61 function z(L) {
62 var M = (L || "mGen") + (++i);
63 return M
64 }
65 // 微信操作
66 if (ifWeixin) { // if navigitor is weixin
67 if (window.WeixinJSBridge && WeixinJSBridge.invoke) {
68 r()
69 } else {
70 document.addEventListener("WeixinJSBridgeReady", r, !1)
71 }
72 }
73
74 // 如果存在js框架
75 if (Query) {
76 selector = window.$;
77 Hquery = window.$
78 } else {
79 selector = function(obj) {
80 if (typeof obj == "object") {
81 return obj
82 }
83 return document.querySelector(obj);
84 };
85 if (!window.$) {
86 window.$ = Hquery = selector
87 } else {
88 Hquery = window.$
89 }
90 }
91 window.onblur = function() {
92 for (var L = 0; L < g.length; L++) {
93 clearTimeout(g[L])
94 }
95 };
96 // 设置cookie。
97 function e(N) {
98 var M = document.cookie.indexOf(N + "=");
99 if (M == -1) {
100 return ""
101 }
102 M = M + N.length + 1;
103 var L = document.cookie.indexOf(";", M);
104 if (L == -1) {
105 L = document.cookie.length
106 }
107 return document.cookie.substring(M, L)
108 }
109 // 设置cookie
110 function l(N, P, L, Q, O) {
111 var R = N + "=" + escape(P);
112 if (L != "") {
113 var M = new Date();
114 M.setTime(M.getTime() + L * 24 * 3600 * 1000);
115 R += ";expires=" + M.toGMTString()
116 }
117 if (Q != "") {
118 R += ";path=" + Q
119 }
120 if (O != "") {
121 R += ";domain=" + O
122 }
123 document.cookie = R
124 }
125
126 // 打开的链接集合
127 function F(L) {
128 var url = {
129 downAppURl: "http://h5.m.jd.com/active/download/download.html?channel=jd-m",
130 downAppIos: "http://union.m.jd.com/download/go.action?to=http%3A%2F%2Fitunes.apple.com%2Fcn%2Fapp%2Fid414245413&client=apple&unionId=12532&subunionId=m-top&key=e4dd45c0f480d8a08c4621b4fff5de74",
131 downWeixin: "http://a.app.qq.com/o/simple.jsp?pkgname=com.jingdong.app.mall&g_f=991850",
132 downIpad: "https://itunes.apple.com/cn/app/jing-dong-hd/id434374726?mt=8",
133 inteneUrl: "openApp.jdMobile://360buy?type=1",
134 inteneUrlParams: null,
135 openAppBtnId: "",
136 closePanelBtnId: "",
137 closePanelId: "",
138 closeCallblack: null,
139 closeCallblackSource: null,
140 cookieFlag: null,
141 noRecord: false,
142 sourceType: "JSHOP_SOURCE_TYPE",
143 sourceValue: "JSHOP_SOURCE_VALUE",
144 openAppEventId: "MDownLoadFloat_OpenNow",
145 closePanelEventId: "MDownLoadFloat_Close"
146 };
147 if (L) {
148 for (var M in L) {
149 if (M && L[M]) {
150 url[M] = L[M]
151 }
152 }
153 }
154 return url
155 }
156 // 敲黑板 重点内容。看京东是怎么解决兼容问题的。
157 function openApp(N, L) { // openApp
158 var R = h(N); //获取相对应的url
159 var O = null;
160 if (ifWeixin) { // 如果是微信端
161 var M = null;
162 if (j) {
163 M = R
164 } else {
165 M = N.downWeixin
166 }
167 location.href = M; // 直接使用location.href打开
168 return
169 }
170 if (ifiPad) { // 如果是ipad
171 O = N.downIpad
172 } else {
173 if (ifiPhone) { // 如果是iphone
174 O = N.downAppIos
175 } else {
176 O = N.downAppURl
177 }
178 }
179
180 if (ifChrome) { // 如果是chrome
181 if (ifAndroid) { //安卓浏览器
182 var Q = R;
183 R = y(Q);
184 // 延后50毫秒
185 setTimeout(function() {
186 window.location.href = R
187 }, 50)
188 }
189 }
190 if (ifSafari && version >= 9) { // 判断safari版本 如果大于9
191 setTimeout(function() { // 必须要使用settimeout
192 var S = document.createElement("a"); //创建a元素
193 S.setAttribute("href", R), S.style.display = "none", document.body.appendChild(S);
194 var T = document.createEvent("HTMLEvents"); // 返回新创建的 Event 对象,具有指定的类型。
195 T.initEvent("click", !1, !1)// 初始化新事件对象的属性, S.dispatchEvent(T) // 绑定事件
196 }, 0)
197 } else {
198 document.querySelector("#" + iframe).src = R // 将iframe增加src
199 }
200 var P = Date.now();
201 setTimeout(function() {
202 if (L) {
203 var S = setTimeout(function() {
204 x(P, O)
205 }, 1500);
206 g.push(S)
207 }
208 }, 100)
209 }
210 // x方法
211 function x(N, downUrl) {
212 var L = Date.now();
213 if (N && (L - N) < (1500 + 200)) {
214 window.location.href = downUrl
215 }
216 }
217
218 function h(N) {
219 var V = [];
220 var P = N.inteneUrlParams;
221 var T = {
222 category: "jump",
223 des: "productDetail"
224 };
225 if (N.sourceType && N.sourceValue) {
226 T.sourceType = N.sourceType;
227 T.sourceValue = N.sourceValue;
228 if (P && !P.sourceType && !P.sourceValue) {
229 P.sourceType = N.sourceType;
230 P.sourceValue = N.sourceValue
231 }
232 }
233 if (P) {
234 for (var U in P) {
235 if (U && P[U]) {
236 V.push('"' + U + '":"' + P[U] + '"')
237 }
238 }
239 } else {
240 for (var U in T) {
241 if (U && T[U]) {
242 V.push('"' + U + '":"' + T[U] + '"')
243 }
244 }
245 }
246 try {
247 var Q = MPing.EventSeries.getSeries();
248 if (Q) {
249 var W = JSON.parse(Q);
250 W.jdv = encodeURIComponent(e("__jdv"));
251 W.unpl = encodeURIComponent(e("unpl"));
252 W.mt_xid = encodeURIComponent(e("mt_xid"));
253 W.mt_subsite = encodeURIComponent(e("mt_subsite"))
254 }
255 var S = {
256 mt_subsite: encodeURIComponent(e("mt_subsite")),
257 __jdv: encodeURIComponent(e("__jdv")),
258 unpl: encodeURIComponent(e("unpl")),
259 __jda: encodeURIComponent(e("__jda"))
260 };
261 Q = JSON.stringify(W);
262 V.push('"m_param":' + Q);
263 V.push('"SE":' + JSON.stringify(S))
264 } catch (R) {
265 V.push('"m_param":null')
266 }
267 var M = "{" + V.join(",") + "}";
268 var O = N.inteneUrl.split("?");
269 var L = null;
270 if (O.length == 2) {
271 L = O[0] + "?" + O[1] + "¶ms=" + M
272 } else {
273 L = O[0] + "?params=" + M
274 }
275 return L
276 }
277
278 function y(L) {
279 return "intent://m.jd.com/#Intent;scheme=" + L + ";package=com.jingdong.app.mall;end"
280 }
281
282 function n(L) {
283 if (L.openAppBtnId) {
284 B[L.openAppBtnId] = L;
285 G(L.openAppBtnId, L.openAppEventId);
286 bind(L.openAppBtnId, "click", function() {
287 var P = this.getAttribute("id");
288 var M = B[P];
289 if (!t) {
290 var N = document.createElement("iframe");
291 N.id = iframe;
292 document.body.appendChild(N);
293 document.getElementById(iframe).style.display = "none";
294 document.getElementById(iframe).style.width = "0px";
295 document.getElementById(iframe).style.height = "0px";
296 t = true
297 }
298 var O = M.cookieFlag ? "downloadAppPlugIn_downCloseDate_" + M.cookieFlag : "downloadAppPlugIn_downCloseDate";
299 l(O, Date.now() + "_2592000000", 60, "/", "m.jd.com");
300 l(O, Date.now() + "_2592000000", 60, "/", "m.jd.hk");
301 openApp(M, true)
302 })
303 }
304 }
305
306 function D(M) {
307 if (M.closePanelBtnId && M.closePanelId) {
308 B[M.closePanelBtnId] = M;
309 G(M.closePanelBtnId, M.closePanelEventId);
310 var Q = M.cookieFlag ? "downloadAppPlugIn_downCloseDate_" + M.cookieFlag : "downloadAppPlugIn_downCloseDate";
311 var O = e(Q);
312 var P = null;
313 if (O) {
314 P = O.split("_");
315 if (P.length == 2) {
316 P[0] = parseInt(P[0], 10);
317 P[1] = parseInt(P[1], 10)
318 } else {
319 P = null
320 }
321 }
322 var L = Date.now();
323 if (Html5Plus() || (!M.noRecord && P && P.length == 2 && (L - P[0]) < P[1])) {
324 document.querySelector("#" + M.closePanelId).style.display = "none";
325 if (M.closeCallblack) {
326 var N = M.closeCallblackSource ? M.closeCallblackSource : null;
327 M.closeCallblack.call(N)
328 }
329 return
330 } else {
331 document.querySelector("#" + M.closePanelId).style.display = "block"
332 }
333 bind(M.closePanelBtnId, "click", function() {
334 var U = this.getAttribute("id");
335 var R = B[U];
336 var T = R.cookieFlag ? "downloadAppPlugIn_downCloseDate_" + R.cookieFlag : "downloadAppPlugIn_downCloseDate";
337 if (!R.noRecord) {
338 l(T, Date.now() + "_259200000", 60, "/", "m.jd.com");
339 l(T, Date.now() + "_259200000", 60, "/", "m.jd.hk")
340 }
341 document.querySelector("#" + R.closePanelId).style.display = "none";
342 if (R.closeCallblack) {
343 var S = R.closeCallblackSource ? R.closeCallblackSource : null;
344 R.closeCallblack.call(S)
345 }
346 })
347 }
348 }
349
350 function Html5Plus() { // htmlplus
351 if (Navigator.indexOf("Html5Plus") >= 0) {
352 return true
353 } else {
354 return false
355 }
356 }
357
358 function G(P, M) {
359 try {
360 var O = document.getElementById(P);
361 var L = O.className;
362 if (L) {
363 L = L + " J_ping"
364 } else {
365 L = "J_ping"
366 }
367 O.className = L;
368 O.setAttribute("report-eventid", M)
369 } catch (N) {}
370 }
371
372 function C(L) {
373 var M = F(L);
374 n(M);
375 D(M)
376 }
377 Hquery.downloadAppPlugIn = C;
378 Hquery.downloadAppPlugInOpenApp = function(L) {
379 var M = F(L);
380 openApp(M);
381 }
382 });