-
Notifications
You must be signed in to change notification settings - Fork 139
/
Copy pathindex.js
231 lines (201 loc) · 7.25 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/**
* @author alanzhang
* @date 2016-07-15
* @overview 测试在浏览器中打开native App;
*
*/
var extend = require('extend');
var browser = require('./browser.js');
/**
* [defautlConfig APP默认配置]
* @private
* @type {Object}
*/
var defautlConfig = {
// 协议头
PROTOCAL:'',
// 主页
HOME: '',
// 唤起失败时的跳转链接
FAILBACK: {
ANDROID: '',
IOS:''
},
// Android apk 相关信息
APK_INFO: {
PKG: '',
CATEGORY: 'android.intent.category.DEFAULT',
ACTION: 'android.intent.action.VIEW'
},
// 唤起超时时间,超时则跳转到下载页面
LOAD_WAITING: 3000
};
/**
* [util 创建A标签]
* @private
* @type {Object}
*/
var util = {
hiddenStyle:'display:none;width:0px;height:0px;',
/**
* [createIfr 创建iframe并隐藏,未加入document中]
* @param {String} src [iframe的src]
* @return {Element} [iframe]
*/
createIfr: function(src){
var iframe = document.createElement('iframe');
iframe.className = 'call_up_iframe';
iframe.src = src;
iframe.style.cssText = this.hiddenStyle;
return iframe;
},
/**
* [createALink 创建A标签并隐藏,未加入document中]
* @param {String} href [a的href]
* @return {Element} [a标签]
*/
createALink: function(href){
var aLink = document.createElement("a");
aLink.className = 'call_up_a_link';
aLink.href = href;
aLink.style.cssText = this.hiddenStyle;
return aLink;
},
/**
* [isDocHidden docuement是否已隐藏]
* @return {Boolean} [description]
*/
isDocHidden: function(){
return document.hidden || document.webkitHidden || document.msHidden;
},
/**
* [visibilityChangeName 兼容visibilityChange]
* @return {String} [description]
*/
visibilityChangeName: function(){
var visibilityChange;
if (typeof document.hidden !== 'undefined') {
visibilityChange = 'visibilitychange';
} else if (typeof document.msHidden !== 'undefined') {
visibilityChange = 'msvisibilitychange';
} else if (typeof document.webkitHidden !== 'undefined') {
visibilityChange = 'webkitvisibilitychange';
}
return visibilityChange;
}
};
function Callup(config){
if (!config) {
return;
}
// 合并参数
this.appConfig = extend({},defautlConfig,config,true);
}
extend(Callup.prototype,{
/**
* [generateSchema 根据不同的场景及UA生成最终应用的schema]
* @param {schema} [schemaURI] [需要使用的schema字符串,如果login,会和协议组装成app可识别的协议]
* @return {Sring} [可用的schema]
*/
generateSchema: function(schemaURI) {
var schemaStr = '';
// 如果未定义schema,则根据当前路径来映射
if (!schemaURI) {
schemaStr = this.appConfig.HOME;
// 在schema省略时,可以根据当前页面的url,设置不同的默认值
} else {
schemaStr = schemaURI;
}
// 如果是安卓chrome浏览器,则通过intent方式打开
// UC/QQ浏览器被识别为chrome,排除之
if (browser.isChrome() && browser.isAndroid() && browser.isUC() === false && browser.isQQBrowser() === false) {
schemaStr = 'intent://' + schemaStr +'#Intent;' +
'scheme=' + this.appConfig.PROTOCAL + ';'+
'package=' + this.appConfig.APK_INFO.PKG + ';'+
'category=' + this.appConfig.APK_INFO.CATEGORY + ';'+
'action=' + this.appConfig.APK_INFO.ACTION + ';'+
'S.browser_fallback_url=' + encodeURIComponent(this.appConfig.FAILBACK.ANDROID) + ';' +
'end';
} else {
schemaStr = this.appConfig.PROTOCAL + '://' + schemaStr;
}
return schemaStr;
},
/**
* [loadSchema 加载schema,打开app]
* @param {Object} config [打开时的配置]
* @return {undefined}
*/
loadSchema: function(config){
// 需要使用的schema
var schemaUrl = this.generateSchema(config.targetURI);
var body = document.body;
// Android 微信不支持schema唤醒,必须提前加入腾讯的白名单
// 百度浏览器会拦截schema,所以直接跳下载页
// QQ,weobo 内也直接跳转下载页
if (browser.isWx() || browser.isBaidu()
|| (browser.isIOS() && browser.isMobileQQ())
|| (browser.isIOS() && browser.isAlipay())
|| browser.isWeibo()) {
if (browser.isAndroid()) {
window.location.href = this.appConfig.FAILBACK.ANDROID;
} else if(browser.isIOS()){
window.location.href = this.appConfig.FAILBACK.IOS;
}
// Android chrome 不支持iframe 方式唤醒
// 适用:chrome,leibao,mibrowser,opera,360,UC,qq浏览器
} else if (browser.isChrome() && browser.isAndroid()
|| browser.isUC()
|| browser.isSafari()
|| browser.isQQBrowser()) {
var aLink = util.createALink(schemaUrl);
body.appendChild(aLink);
aLink.click();
// 其他浏览器
// 适用:sogou,firefox,mobileQQ
} else {
var iframe = util.createIfr(schemaUrl);
body.appendChild(iframe);
}
this.checkLoadStatus(config.success,config.fail);
},
/**
* [checkLoadStatus 通过setTimeout来检查App是否启动]
* @private
* @return {undefined}
*/
checkLoadStatus: function(success,fail){
var start = new Date().getTime();
var that = this;
var loadTimer = setTimeout(function() {
if (util.isDocHidden()) {
return;
}
// 如果app启动,浏览器最小化进入后台,则计时器存在推迟或者变慢的问题
// 那么代码执行到此处时,时间间隔必然大于设置的定时时间
if (Date.now() - start > that.appConfig.LOAD_WAITING + 200) {
//console.log('come back from app')
// 如果浏览器未因为app启动进入后台,则定时器会准时执行,故应该跳转到下载页
} else {
if (fail) {
fail();
} else {
window.location.href = browser.isIOS() ? that.appConfig.FAILBACK.IOS : that.appConfig.FAILBACK.ANDROID;
}
}
}, this.appConfig.LOAD_WAITING);
// 当本地app被唤起,则页面会隐藏掉,就会触发pagehide与visibilitychange事件
// 在部分浏览器中可行,网上提供方案,作hack处理
document.addEventListener(util.visibilityChangeName(), function() {
if (util.isDocHidden) {
clearTimeout(loadTimer);
}
}, false);
// pagehide 必须绑定到window
window.addEventListener('pagehide', function() {
clearTimeout(loadTimer);
success && success();
}, false);
}
});
module.exports = Callup;