| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import appSettings from '@/core/config/app-settings'
- import { runWithoutHttpErrorToast } from '@/core/http/interceptor-registry'
- let blocked = false
- let modalOpen = false
- let probeInflight = null
- let i18nRef = null
- const listeners = new Set()
- function t(key, fallback) {
- if (!i18nRef) return fallback
- try {
- const v = i18nRef.t(key)
- return v && v !== key ? v : fallback
- } catch (_) {
- return fallback
- }
- }
- function notify() {
- listeners.forEach((fn) => {
- try {
- fn(blocked)
- } catch (_) {}
- })
- }
- function setBlocked(next) {
- const v = !!next
- if (blocked === v) return
- blocked = v
- notify()
- }
- export function isNetworkBlocked() {
- return blocked
- }
- export function subscribeNetworkBlock(listener) {
- if (typeof listener === 'function') {
- listeners.add(listener)
- listener(blocked)
- }
- return () => listeners.delete(listener)
- }
- function getNetworkTypeAsync() {
- return new Promise((resolve) => {
- uni.getNetworkType({
- success: (res) => resolve((res && res.networkType) || 'unknown'),
- fail: () => resolve('none')
- })
- })
- }
- function probeApiReachable() {
- const base = (appSettings.appurl || '').replace(/\/$/, '')
- if (!base) return Promise.resolve(true)
- // 探测根路径常会 404,但会触发全局拦截器 toast「API 接口不存在」
- return runWithoutHttpErrorToast(
- () =>
- new Promise((resolve) => {
- uni.request({
- url: `${base}/`,
- method: 'GET',
- timeout: 6000,
- success: (res) => {
- const code = res && res.statusCode
- resolve(code >= 200 && code < 500)
- },
- fail: () => resolve(false)
- })
- })
- )
- }
- /**
- * 是否具备可用网络(无网络 / 系统禁止本 App 使用网络时返回 false)
- */
- export async function checkNetworkAccess() {
- const type = await getNetworkTypeAsync()
- if (type === 'none') return false
- // 已连接 Wi‑Fi/蜂窝但仍可能被系统禁止本 App 使用网络,用轻量请求探测
- const reachable = await probeApiReachable()
- return reachable
- }
- export async function refreshNetworkAccess() {
- // #ifndef APP-PLUS
- setBlocked(false)
- return true
- // #endif
- // #ifdef APP-PLUS
- if (probeInflight) return probeInflight
- probeInflight = checkNetworkAccess()
- .then((ok) => {
- setBlocked(!ok)
- return ok
- })
- .finally(() => {
- probeInflight = null
- })
- return probeInflight
- // #endif
- }
- export function openNetworkSettings() {
- // #ifdef APP-PLUS
- try {
- const os = (plus.os.name || '').toLowerCase()
- if (os === 'ios') {
- plus.runtime.openURL('app-settings:')
- return
- }
- if (os === 'android') {
- const main = plus.android.runtimeMainActivity()
- const Intent = plus.android.importClass('android.content.Intent')
- const Settings = plus.android.importClass('android.provider.Settings')
- const intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS)
- main.startActivity(intent)
- return
- }
- } catch (e) {
- console.warn('[network-guard] open settings failed', e)
- }
- // #endif
- if (typeof uni.openAppAuthorizeSetting === 'function') {
- uni.openAppAuthorizeSetting({})
- }
- }
- export function promptNetworkRequired() {
- if (!blocked || modalOpen) return
- modalOpen = true
- uni.showModal({
- title: t('networkGuard.title', '需要网络'),
- content: t(
- 'networkGuard.content',
- '当前无法访问网络。请在系统设置中允许本应用使用无线局域网与蜂窝数据,否则无法继续使用。'
- ),
- confirmText: t('networkGuard.confirm', '去设置'),
- cancelText: t('networkGuard.cancel', '知道了'),
- showCancel: true,
- success: (res) => {
- modalOpen = false
- if (res.confirm) openNetworkSettings()
- },
- fail: () => {
- modalOpen = false
- }
- })
- }
- // #ifdef APP-PLUS
- let nativeMask = null
- function ensureNativeMask() {
- if (nativeMask) return nativeMask
- nativeMask = new plus.nativeObj.View(
- 'hl88-network-blocker',
- {
- top: '0px',
- left: '0px',
- width: '100%',
- height: '100%',
- backgroundColor: 'rgba(0,0,0,0.01)'
- },
- []
- )
- nativeMask.interceptTouchEvent(true)
- nativeMask.addEventListener('click', () => {
- promptNetworkRequired()
- })
- return nativeMask
- }
- function syncNativeMask() {
- try {
- const mask = ensureNativeMask()
- if (blocked) mask.show()
- else mask.hide()
- } catch (e) {
- console.warn('[network-guard] native mask', e)
- }
- }
- // #endif
- function onBlockStateChange() {
- // #ifdef APP-PLUS
- syncNativeMask()
- // #endif
- }
- let started = false
- export function startNetworkAccessGuard(i18n) {
- // #ifndef APP-PLUS
- return
- // #endif
- // #ifdef APP-PLUS
- if (started) return
- started = true
- i18nRef = i18n
- subscribeNetworkBlock(onBlockStateChange)
- const kickoff = () => refreshNetworkAccess()
- if (typeof plus !== 'undefined') {
- kickoff()
- } else if (typeof document !== 'undefined') {
- document.addEventListener('plusready', kickoff, false)
- } else {
- kickoff()
- }
- if (typeof uni.onNetworkStatusChange === 'function') {
- uni.onNetworkStatusChange(() => {
- refreshNetworkAccess()
- })
- }
- // #endif
- }
- export function stopNetworkAccessGuard() {
- // #ifndef APP-PLUS
- return
- // #endif
- // #ifdef APP-PLUS
- started = false
- if (nativeMask) {
- try {
- nativeMask.hide()
- nativeMask.close()
- } catch (_) {}
- nativeMask = null
- }
- // #endif
- }
|