技术实现

直接用window.location.href的方法解决,这个方法的前提条件是需要知道自己app对应的打开协议,如贴吧APP,协议为:com.baidu.tieba://(下边以百度贴吧为例)

1
<!-- a标签点击打开的动作,在click事件中注册 -->
2
<a href="javascript:;" id="openApp">贴吧客户端</a>
3
<script type="text/javascript">
4
    document.getElementById('openApp').onclick = function(e){
5
        window.location.href = "com.baidu.tieba://";
6
        window.setTimeout(function(){
7
            window.location.href = "https://itunes.apple.com/cn/app/id477927812";//打开app下载地址,由app开发人员提供
8
        },2000)
9
    };
10
</script>

因为Android和iOS的下载包和协议是不同的所以需要判断一下用户的系统类型

1
<body>
2
    <a href="javascript:;" id="openApp">贴吧客户端</a>
3
</body>
4
5
<script type="text/javascript">
6
    document.getElementById('openApp').onclick = function(e){
7
        if(navigator.userAgent.match(/(iPhone|iPod|iPad);?/i))
8
           {
9
            window.location.href = "com.baidu.tieba://";//ios app协议
10
            window.setTimeout(function() {
11
                window.location.href = "https://itunes.apple.com/cn/app/id477927812";
12
            }, 2000)
13
           }
14
        if(navigator.userAgent.match(/android/i))
15
           {
16
            window.location.href = "com.baidu.tieba://app";//android app协议
17
            window.setTimeout(function() {
18
                window.location.href = "https://****.apk";//android 下载地址
19
            }, 2000)    
20
        }
21
    };
22
</script>

但是用window.location.href方法的话当手机中有目标应用时,应用打开,但是浏览器也会跳转到下载页面,而且微信浏览器不支持打开、下载第三方app,所以做微信活动页的coder们当遇到需要实现该需求时所考虑的就更多了。

京东针对于这个问题的解决方案。如下

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
});

这个虽然看起来比较繁琐,而且得着实的理解一下,但是一个比较全面的解决办法