<

{{title}}

{{file.summary.functions.pct}}%

Functions
{{file.summary.functions.covered}}/{{file.summary.functions.total}}

{{file.summary.branches.pct}}%

Branches
{{file.summary.branches.covered}}/{{file.summary.branches.total}}

{{file.summary.lines.pct}}%

Lines
{{file.summary.lines.covered}}/{{file.summary.lines.total}}
          
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                
import webview from '@ohos.web.webview'; 
import connection from '@ohos.net.connection'; 
 
/** 
 * `javaScriptOnDocumentStart` 脚本项。 
 */ 
interface ScriptItemLike { 
  script: string; 
  scriptRules: string[]; 
} 
 
/** 
 * 将设备网络状态实时同步到 H5 的 `navigator.onLine`。 
 */ 
export class NetworkStateInjector { 
  private netCon: connection.NetConnection | null = null; 
  private controller: webview.WebviewController | null = null; 
 
  /** 在页面加载前注入的 JS 脚本,重写 `navigator.onLine` 并监听网络变化。 */ 
  private static readonly DOCUMENT_START_SCRIPT: string = 
    '(function(){try{' + 
    'if(window.__qianOnline===undefined){window.__qianOnline=true;}' + 
    'try{Object.defineProperty(navigator,"onLine",{configurable:true,get:function(){return window.__qianOnline!==false;}});}catch(e){}' + 
    'window.__qianSetOnline=function(v){' + 
    'var prev=window.__qianOnline;' + 
    'window.__qianOnline=!!v;' + 
    'if(prev!==window.__qianOnline){' + 
    'try{window.dispatchEvent(new Event(window.__qianOnline?"online":"offline"));}catch(e){}' + 
    '}' + 
    '};' + 
    '}catch(e){}})();'; 
 
  /** 获取 document_start 注入脚本。 */ 
  public static getDocumentStartScript(): string { 
    return NetworkStateInjector.DOCUMENT_START_SCRIPT; 
  } 
 
  /** 绑定 WebView 控制器并启动网络监听。 */ 
  public attach(controller: webview.WebviewController): void { 
    this.controller = controller; 
    this.installDocumentStartScript(); 
    this.startListen(); 
  } 
 
  /** 解绑并释放资源。 */ 
  public detach(): void { 
    this.stopListen(); 
    this.controller = null; 
  } 
 
  /** 注册 document_start 脚本注入。 */ 
  private installDocumentStartScript(): void { 
    if (this.controller === null) { 
      return; 
    } 
    try { 
      const scriptItems: ScriptItemLike[] = [{ 
        script: NetworkStateInjector.DOCUMENT_START_SCRIPT, 
        scriptRules: ['*'] 
      }]; 
      // 通过 ESObject cast 调用,因为老版 .d.ts 未导出 javaScriptOnDocumentStart 
      const ctrl: ESObject = this.controller as ESObject; 
      ctrl.javaScriptOnDocumentStart(scriptItems); 
    } catch (_e) { 
      // ignore 
    } 
  } 
 
  /** 同步网络状态到 H5 端。 */ 
  private updateRuntime(online: boolean): void { 
    if (this.controller === null) { 
      return; 
    } 
    const value: string = online ? 'true' : 'false'; 
    const script: string = 'try{window.__qianSetOnline&&window.__qianSetOnline(' + value + ');}catch(e){}'; 
    try { 
      this.controller.runJavaScript(script); 
    } catch (_e) { 
      // ignore 
    } 
  } 
 
  /** 查询系统网络状态并同步。 */ 
  private refreshFromSystem(): void { 
    try { 
      connection.getDefaultNet().then((handle: connection.NetHandle) => { 
        connection.getNetCapabilities(handle).then((cap: connection.NetCapabilities) => { 
          const hasBearer: boolean = cap.bearerTypes !== undefined && cap.bearerTypes.length > 0; 
          const validated: boolean = cap.networkCap !== undefined 
            && cap.networkCap.indexOf(connection.NetCap.NET_CAPABILITY_VALIDATED) >= 0; 
          this.updateRuntime(hasBearer && validated); 
        }).catch((_e: Object): void => { 
          this.updateRuntime(true); 
        }); 
      }).catch((_e: Object): void => { 
        this.updateRuntime(false); 
      }); 
    } catch (_e) { 
      this.updateRuntime(true); 
    } 
  } 
 
  /** 启动网络状态订阅。 */ 
  private startListen(): void { 
    try { 
      this.netCon = connection.createNetConnection(); 
      this.netCon.on('netAvailable', (_handle: connection.NetHandle): void => { 
        this.refreshFromSystem(); 
      }); 
      this.netCon.on('netLost', (_handle: connection.NetHandle): void => { 
        this.updateRuntime(false); 
      }); 
      this.netCon.on('netCapabilitiesChange', 
        (_info: connection.NetCapabilityInfo): void => { 
          this.refreshFromSystem(); 
        }); 
      this.netCon.register((_e: Object): void => { 
        // ignore register error 
      }); 
    } catch (_e) { 
      // ignore 
    } 
  } 
 
  private stopListen(): void { 
    if (this.netCon !== null) { 
      try { 
        this.netCon.unregister((_e: Object): void => { 
          // ignore 
        }); 
      } catch (_e) { 
        // ignore 
      } 
      this.netCon = null; 
    } 
  } 
} 

              
Code coverage generated by bjc at {{date}}