t-comm
Version:
专业、稳定、纯粹的工具库
363 lines (360 loc) • 15.1 kB
JavaScript
import { _ as __assign } from '../tslib.es6-096fffdd.js';
import { initEnv } from '../env/env.mjs';
import { loader } from '../loader/little-loader.mjs';
import { merge as _merge } from '../lodash-mini/merge.mjs';
import { closeWebView } from '../msdk/msdk.mjs';
import '@babel/runtime/helpers/typeof';
// const closeWebView = () => console.log('closeWebView');
// type ILaunchAppParams = any;
// type IEnv = any;
/**
* @description 通过 location.href 来拉起
* @param {String} scheme 必须,协议
* @ignore
*/
function launchByHref(scheme) {
if (!scheme) return;
var win = window !== top && top ? top : window;
win.location.href = scheme;
}
/**
* @description 通过可见性来判断是否唤起成功
* @param {Object} params
* @param {Function} params.successCallback 可选,唤起成功回调
* @param {Function} params.failCallback 可选,唤起失败回调
* @param {int} params.delay 可选,延迟多少时间后,判断是否拉起成功
* @ignore
*/
function checkLaunchResultByVisibility(_a) {
var successCallback = _a.successCallback,
failCallback = _a.failCallback,
_b = _a.delay,
delay = _b === void 0 ? 3500 : _b;
var hasCallback = false;
var hiddenProperty = 'hidden';
// visibilityChangeEvent
if ('hidden' in document) {
hiddenProperty = 'hidden';
} else if ('webkitHidden' in document) {
hiddenProperty = 'webkitHidden';
} else if ('mozHidden' in document) {
hiddenProperty = 'mozHidden';
}
var visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
// eventHandler
var onVisibilityChange = function onVisibilityChange() {
if (document[hiddenProperty]) {
hasCallback = true;
successCallback === null || successCallback === void 0 ? void 0 : successCallback();
}
};
document.removeEventListener(visibilityChangeEvent, onVisibilityChange);
document.addEventListener(visibilityChangeEvent, onVisibilityChange);
setTimeout(function () {
if (!hasCallback) {
failCallback === null || failCallback === void 0 ? void 0 : failCallback();
}
document.removeEventListener(visibilityChangeEvent, onVisibilityChange);
}, delay);
}
/**
* @description 通过定时器来判断是否唤起成功,适用于安卓
* @param {Object} params
* @param {Function} params.successCallback 可选,唤起成功回调
* @param {Function} params.failCallback 可选,唤起失败回调
* @ignore
*/
function checkLaunchResultByTimer(_a) {
var successCallback = _a.successCallback,
failCallback = _a.failCallback,
_b = _a.maxTime,
maxTime = _b === void 0 ? 3000 : _b;
var startTime = Date.now();
// document.hidden 兼容性
var hiddenProperty = 'hidden';
if ('hidden' in document) {
hiddenProperty = 'hidden';
} else if ('webkitHidden' in document) {
hiddenProperty = 'webkitHidden';
} else if ('mozHidden' in document) {
hiddenProperty = 'mozHidden';
}
// 检查定时器是否准确,若拉起 App,页面运行在后台会导致 setInterval 不准
// 对于 Android 来说,setTimeout 不受影响,所以选 setInterval
function check(elsTime) {
if (elsTime > maxTime || document[hiddenProperty]) {
successCallback === null || successCallback === void 0 ? void 0 : successCallback();
} else {
failCallback === null || failCallback === void 0 ? void 0 : failCallback();
}
}
// 启动间隔20ms运行的定时器,并检测累计消耗时间是否超过3000ms,超过则结束
var count = 0;
var interval = setInterval(function () {
count += 1;
var endTime = Date.now();
var duration = endTime - startTime;
if (count >= 100 || duration > maxTime) {
clearInterval(interval);
check(duration);
}
}, 20);
}
/**
* @description 在微信内,需要通过微信 JSSDK API 来唤起
* @param {Object} params
* @param {String} params.appid 必填,供iOS使用
* @param {String} params.weixinScheme 必填,scheme://parameter 通过系统接口拉起第三方app。中文或特殊字符需要encode
* @param {Function} params.successCallback 可选,唤起成功回调
* @param {Function} params.failCallback 可选,唤起失败回调
* @ignore
*/
function launchInWeiXin(_a) {
var appid = _a.appid,
weixinScheme = _a.weixinScheme,
successCallback = _a.successCallback,
failCallback = _a.failCallback;
var sdkUrl = 'https://image-1251917893.file.myqcloud.com/commjs/jweixin-1.6.0.js';
var invokeParams = {
schemeUrl: weixinScheme,
appID: appid
};
var afterInvoke = function afterInvoke(res) {
var _a;
console.log('[launchInWeiXin] result', {
res: res
});
var isSuccess = ((_a = res === null || res === void 0 ? void 0 : res.err_msg) === null || _a === void 0 ? void 0 : _a.indexOf('ok')) !== -1;
if (isSuccess) {
successCallback === null || successCallback === void 0 ? void 0 : successCallback();
} else {
failCallback === null || failCallback === void 0 ? void 0 : failCallback();
}
};
var onBridgeReady = function onBridgeReady() {
console.log('onBridgeReady...');
loader(sdkUrl, function () {
var _a;
console.log('[onBridgeReady]');
(_a = window.WeixinJSBridge) === null || _a === void 0 ? void 0 : _a.invoke('launchApplication', invokeParams, afterInvoke);
});
};
// WeixinJSBridge 接口加载后再 invoke
if (typeof window.WeixinJSBridge === 'undefined') {
console.log('WeixinJSBridge undefined');
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
console.log('WeixinJSBridge not undefined');
onBridgeReady();
}
}
/**
* @description 在手Q内,调用手Q JSSDK API 唤起
* @param {Object} params
* @param {Object} params.env 必须,环境信息,内部自动传递
* @param {String} params.qqAppScheme 必填,仅供 iOS 使用,scheme://parameter 通过系统接口拉起第三方app。中文或特殊字符需要encode
* @param {String} params.qqAppPackageName 必填,仅供 Android 使用,安装包包名
* @param {Function} params.successCallback 可选,唤起成功回调
* @param {Function} params.failCallback 可选,唤起失败回调
* @ignore
*/
function launchInMobileQQ(_a) {
var env = _a.env,
isUseSchemeParams = _a.isUseSchemeParams,
qqAppScheme = _a.qqAppScheme,
qqAppPackageName = _a.qqAppPackageName,
successCallback = _a.successCallback,
failCallback = _a.failCallback;
// 在手Q下,通过 visibility 事件判断是否成功拉起
var check = function check() {
checkLaunchResultByVisibility({
successCallback: successCallback,
failCallback: failCallback
});
};
// API不支持传参,所以如果 scheme 包含参数,直接拉起
if (isUseSchemeParams) {
launchByHref(qqAppScheme);
check(); // 判断是否拉起
// 无参数,通过 API 拉起
} else {
loader('https://pub.idqqimg.com/qqmobile/qqapi.js?_bid=152', function () {
var scheme = env.isIos ? qqAppScheme : qqAppPackageName;
window.mqq.app.launchApp(scheme);
check(); // 判断是否拉起
});
}
}
/**
* @description 在 iOS 原生浏览器内,直接拉起
* @param {Object} params
* @param {Object} params.env 必须,环境信息,内部自动传递
* @param {String} params.browserAppScheme 必填,scheme://parameter 通过系统接口拉起第三方app。中文或特殊字符需要encode
* @param {Function} params.successCallback 可选,唤起成功回调
* @param {Function} params.failCallback 可选,唤起失败回调
* @ignore
*/
function launchInIOSBrowser(_a) {
var browserAppScheme = _a.browserAppScheme,
successCallback = _a.successCallback,
failCallback = _a.failCallback;
launchByHref(browserAppScheme);
// 检查唤起结果
checkLaunchResultByVisibility({
successCallback: successCallback,
failCallback: failCallback
});
}
/**
* @description 在 Android 原生浏览器内,直接使用原生支持的 Universal Links 形式,但通过 iframe 形式唤起
* @param {Object} params
* @param {String} params.env 必须,环境信息,内部自动传递
* @param {String} params.browserApkScheme 必填,scheme://parameter 通过系统接口拉起第三方app。中文或特殊字符需要encode
* @param {Function} params.successCallback 可选,唤起成功回调
* @param {Function} params.failCallback 可选,唤起失败回调
* @ignore
*/
function launchInAndroidBrowser(_a) {
var browserApkScheme = _a.browserApkScheme,
successCallback = _a.successCallback,
failCallback = _a.failCallback;
// 通过 iframe 唤起
var div = document.createElement('div');
div.style.visibility = 'hidden';
div.innerHTML = "<iframe id=\"scheme\" src=\"".concat(browserApkScheme, "\" scrolling=\"no\" width=\"1\" height=\"1\"></iframe>");
document.body.appendChild(div);
// 通过定时器是否延时来检查是否成功唤起
checkLaunchResultByTimer({
successCallback: successCallback,
failCallback: failCallback
});
}
/**
* @description 兼容微信、手Q、手机原生浏览器、游戏内环境的唤起第三方 APP 方法。用于替代 launch 方法,优化传参以及底层实现。
* @param {Object} args 必须,参数对象
* @param {String} args.appid 必须,用于微信内拉起,微信开放平台的 appID,向游戏公众号管理者索取。
* @param {String} args.weixinScheme 必须,用于微信内拉起,目标 App 的 URL Scheme
* @param {String} args.browserAppScheme 必须,用于 iOS 原生浏览器拉起,目标 App 的 URL Scheme
* @param {String} args.browserApkScheme 必须,用于 Android 原生浏览器拉起,目标 App 的 URL Scheme
* @param {String} args.qqAppScheme 必须,用于 iOS + 手 Q 内拉起,目标 App 的 URL Scheme
* @param {String} args.qqAppPackageName 必须,用于 Android + 手 Q 内拉起,目标 App 的安卓包名,例如 com.tencent.tmgp.sgame
* @param {Boolean} args.isUseSchemeParams 可选,默认 false,scheme 是否携带参数,用于手Q内判断切换拉起方式
* @param {Boolean} args.openMarket 可选,默认 false,若跳转失败,拉起应用下载地址
* @param {String} args.appMarketUrl 可选,默认空,Appstore 下载地址,例如 https://itunes.apple.com/cn/app/id989673964
* @param {String} args.apkMarketUrl 可选,默认空,安卓应用下载地址,例如 market://details?id=com.tencent.tmgp.sgame
* @param {Boolean} args.needRedirect 可选,默认 false,若不跳转下载,是否跳转其他地址
* @param {String} args.redirectUrl 可选,默认空,跳转其他地址,例如某官网地址
* @param {String} args.failTips 可选,默认空,若不跳转下载 or 其他地址,而是开启拉起失败提示,该处填写提示内容
* @param {Function} args.successCallback 可选,默认空,拉起成功回调
* @param {Function} args.failCallback 可选,默认空,拉起失败回调
*/
function launchApp(args) {
var _a;
if (args === void 0) {
args = {};
}
(_a = args === null || args === void 0 ? void 0 : args.Toast) === null || _a === void 0 ? void 0 : _a.showLoading('启动中...');
var env = initEnv();
var baseParams = {
isUseSchemeParams: false,
// 微信内拉起
appid: '',
weixinScheme: '',
// 网页内拉起
browserAppScheme: '',
browserApkScheme: '',
// 手Q内拉起
qqAppScheme: '',
qqAppPackageName: '',
// 唤起失败处理开启优先级:错误回调 > 跳转下载 > 跳转链接 > 弹窗提示
// 如果跳转失败,拉起下载
openMarket: false,
appMarketUrl: '',
apkMarketUrl: '',
// 如果不拉起下载,选择跳转
needRedirect: false,
redirectUrl: '',
// 不拉起下载 or 跳转,通过提示
failTips: '',
// 错误回调
failCallback: null,
// 成功回调
successCallback: null
};
// 合并默认参数
var params = _merge({}, baseParams, __assign({
env: env
}, args));
console.log('[params]', params);
console.log('[env]', env);
// 二次封装失败、成功回调
var customFailCallback = params.failCallback;
var customSuccCallback = params.successCallback;
var onSuccHandler = function onSuccHandler() {
var _a;
(_a = args === null || args === void 0 ? void 0 : args.Toast) === null || _a === void 0 ? void 0 : _a.dismissLoading();
console.log('[launchApp] onSuccHandler');
customSuccCallback === null || customSuccCallback === void 0 ? void 0 : customSuccCallback();
};
// 错误处理:错误回调 > 跳转下载 > 跳转链接 > 弹窗提示
var onFailHandler = function onFailHandler() {
var _a, _b, _c;
console.log('[launchApp] onFailHandler');
(_a = args === null || args === void 0 ? void 0 : args.Toast) === null || _a === void 0 ? void 0 : _a.dismissLoading();
if (customFailCallback) {
customFailCallback();
} else if (params.openMarket) {
if (env.isIOS) {
params.appMarketUrl && (window.location.href = params.appMarketUrl);
} else {
params.apkMarketUrl && (window.location.href = params.apkMarketUrl);
}
if (env.isWeixin && !env.isMiniProgram) {
checkLaunchResultByVisibility({
successCallback: function successCallback() {},
failCallback: function failCallback() {
var _a, _b;
if (params.failTips) {
(_b = (_a = args.Dialog) === null || _a === void 0 ? void 0 : _a.showTipsDialog) === null || _b === void 0 ? void 0 : _b.call(_a, params.failTips);
}
},
delay: 2000
});
}
} else if (params.needRedirect) {
params.redirectUrl && (window.location.href = params.redirectUrl);
} else if (params.failTips !== '') {
(_c = (_b = args.Dialog) === null || _b === void 0 ? void 0 : _b.showTipsDialog) === null || _c === void 0 ? void 0 : _c.call(_b, params.failTips);
}
};
params.failCallback = onFailHandler;
params.successCallback = onSuccHandler;
// 在游戏内
if (env.isInGame) {
closeWebView(); // 关闭当前页面
// 在微信内
} else if (env.isWeixin && !env.isMiniProgram) {
launchInWeiXin(params);
// 在微信小程序内
} else if (env.isWeixin && env.isMiniProgram) {
onFailHandler();
// 在手Q、QQ浏览器内
} else if (env.isQQ) {
launchInMobileQQ(params);
// 原生浏览器 or 其他
} else {
// android
if (env.isAndroid) {
launchInAndroidBrowser(params);
// iOS
} else {
launchInIOSBrowser(params);
}
}
}
export { launchApp };