You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
2.9 KiB

  1. import { Subject } from 'rxjs';
  2. declare global {
  3. interface Window {
  4. WebViewJavascriptBridge: {
  5. callHandler: (
  6. name: string,
  7. args: Record<string, any>,
  8. callback: (res: string) => void
  9. ) => void;
  10. registerHandler: (
  11. name: string,
  12. func: (data: string, callback: (res: string) => void) => void
  13. ) => void;
  14. };
  15. WVJBCallbacks: Array<(bridge: typeof window.WebViewJavascriptBridge) => void>;
  16. }
  17. }
  18. export function setupWebViewJavascriptBridge(
  19. callback: (bridge: typeof window.WebViewJavascriptBridge) => void
  20. ) {
  21. if (window.WebViewJavascriptBridge) {
  22. return callback(window.WebViewJavascriptBridge);
  23. }
  24. if (/android/i.test(navigator.userAgent)) {
  25. document.addEventListener(
  26. 'WebViewJavascriptBridgeReady',
  27. function () {
  28. callback(window.WebViewJavascriptBridge);
  29. },
  30. false
  31. );
  32. } else {
  33. if (window.WVJBCallbacks) {
  34. return window.WVJBCallbacks.push(callback);
  35. }
  36. window.WVJBCallbacks = [callback];
  37. var WVJBIframe = document.createElement('iframe');
  38. WVJBIframe.style.display = 'none';
  39. WVJBIframe.src = 'https://__bridge_loaded__';
  40. document.documentElement.appendChild(WVJBIframe);
  41. setTimeout(function () {
  42. document.documentElement.removeChild(WVJBIframe);
  43. }, 0);
  44. }
  45. }
  46. type ShowModelParam = Partial<{
  47. title: string; // 非必填,但 title 和 content 至少要填一个
  48. content: string; // 非必填,但 title 和 content 至少要填一个
  49. contentAlignCenter: boolean; // 内容文本水平居中? 默认 false, 居左
  50. showCancel: boolean; // 默认 true
  51. cancelText: string; //默认 '取消'
  52. // cancelColor: string; // 默认'#333333'
  53. confirmText: string; // 默认 '确定'
  54. // confirmColor: string; // 默认 APP主题色
  55. }>;
  56. // 是否运行在 原生APP 的 WebView 中
  57. const appWebview = navigator.userAgent.includes('iFlyTop-mobile');
  58. const bridgeSub = new Subject<{ func: string; data: Record<string, any> | any[] }>();
  59. export const bridgeOb = bridgeSub.asObservable();
  60. export function registerBridgeFunc() {
  61. const jsFuncs = ['funcInJs'];
  62. jsFuncs.forEach((funcName) => {
  63. window.WebViewJavascriptBridge.registerHandler(funcName, (data, callback) => {
  64. bridgeSub.next({ func: funcName, data: JSON.parse(data) });
  65. callback(JSON.stringify({ success: true }));
  66. });
  67. });
  68. }
  69. export default class Bridge {
  70. static register(name: string, func: (data: string, callback: (res: string) => void) => void) {
  71. if (appWebview) {
  72. window.WebViewJavascriptBridge.registerHandler(name, func);
  73. }
  74. }
  75. static showModal(param: ShowModelParam) {
  76. if (appWebview) {
  77. return new Promise<'confirm' | 'cancel'>((resolve) => {
  78. window.WebViewJavascriptBridge.callHandler('showModal', param, (res) => {
  79. resolve(res as 'confirm' | 'cancel');
  80. });
  81. });
  82. } else {
  83. return Promise.resolve('confirm' as const);
  84. }
  85. }
  86. }